diff options
author | yang-g <yangg@google.com> | 2015-07-28 09:20:08 -0700 |
---|---|---|
committer | yang-g <yangg@google.com> | 2015-07-28 09:20:08 -0700 |
commit | e8afb2338f4d8ebb5cdab093aac342a4378604ab (patch) | |
tree | faafdf066ca220466cf98500a1656292fb24188b /src | |
parent | 60b653bf35fad97f9b0187922ccea9cfb04f635d (diff) | |
parent | 8e06c2e62e0be2606598dd1f2a6582b585364520 (diff) |
Merge remote-tracking branch 'upstream/master' into jitter
Diffstat (limited to 'src')
168 files changed, 3038 insertions, 1310 deletions
diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc index c80bd933ae..e0c1bcda19 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)); @@ -334,13 +334,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"); @@ -353,13 +353,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/compiler/python_generator.cc b/src/compiler/python_generator.cc index 724b69c703..2982a89fad 100644 --- a/src/compiler/python_generator.cc +++ b/src/compiler/python_generator.cc @@ -249,7 +249,7 @@ bool GetModuleAndMessagePath(const Descriptor* type, do { message_path.push_back(path_elem_type); path_elem_type = path_elem_type->containing_type(); - } while (path_elem_type != nullptr); + } while (path_elem_type); // implicit nullptr comparison; don't be explicit grpc::string file_name = type->file()->name(); static const int proto_suffix_length = strlen(".proto"); if (!(file_name.size() > static_cast<size_t>(proto_suffix_length) && diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c index 2457529c16..2cfca399b6 100644 --- a/src/core/channel/client_channel.c +++ b/src/core/channel/client_channel.c @@ -523,7 +523,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/channel/compress_filter.c b/src/core/channel/compress_filter.c index 14e8ca7325..9fc8589fbb 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) { @@ -282,19 +284,19 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, grpc_channel_args_get_compression_algorithm(args); channeld->mdstr_request_compression_algorithm_key = - grpc_mdstr_from_string(mdctx, GRPC_COMPRESS_REQUEST_ALGORITHM_KEY); + grpc_mdstr_from_string(mdctx, GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, 0); channeld->mdstr_outgoing_compression_algorithm_key = - grpc_mdstr_from_string(mdctx, "grpc-encoding"); + grpc_mdstr_from_string(mdctx, "grpc-encoding", 0); for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) { - char *algorith_name; - GPR_ASSERT(grpc_compression_algorithm_name(algo_idx, &algorith_name) != 0); + char *algorithm_name; + GPR_ASSERT(grpc_compression_algorithm_name(algo_idx, &algorithm_name) != 0); channeld->mdelem_compression_algorithms[algo_idx] = grpc_mdelem_from_metadata_strings( mdctx, grpc_mdstr_ref(channeld->mdstr_outgoing_compression_algorithm_key), - grpc_mdstr_from_string(mdctx, algorith_name)); + grpc_mdstr_from_string(mdctx, algorithm_name, 0)); } GPR_ASSERT(!is_last); diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c index 6ae8488070..91125cb149 100644 --- a/src/core/channel/http_client_filter.c +++ b/src/core/channel/http_client_filter.c @@ -233,7 +233,7 @@ static grpc_mdstr *user_agent_from_args(grpc_mdctx *mdctx, tmp = gpr_strvec_flatten(&v, NULL); gpr_strvec_destroy(&v); - result = grpc_mdstr_from_string(mdctx, tmp); + result = grpc_mdstr_from_string(mdctx, tmp, 0); gpr_free(tmp); return result; @@ -260,7 +260,7 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc"); channeld->status = grpc_mdelem_from_strings(mdctx, ":status", "200"); channeld->user_agent = grpc_mdelem_from_metadata_strings( - mdctx, grpc_mdstr_from_string(mdctx, "user-agent"), + mdctx, grpc_mdstr_from_string(mdctx, "user-agent", 0), user_agent_from_args(mdctx, args)); } diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c index 7c798d2fb4..9d89eb9bf2 100644 --- a/src/core/channel/http_server_filter.c +++ b/src/core/channel/http_server_filter.c @@ -250,9 +250,9 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, channeld->http_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "http"); channeld->https_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "https"); channeld->grpc_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "grpc"); - channeld->path_key = grpc_mdstr_from_string(mdctx, ":path"); - channeld->authority_key = grpc_mdstr_from_string(mdctx, ":authority"); - channeld->host_key = grpc_mdstr_from_string(mdctx, "host"); + channeld->path_key = grpc_mdstr_from_string(mdctx, ":path", 0); + channeld->authority_key = grpc_mdstr_from_string(mdctx, ":authority", 0); + channeld->host_key = grpc_mdstr_from_string(mdctx, "host", 0); channeld->content_type = grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc"); diff --git a/src/core/iomgr/iomgr.c b/src/core/iomgr/iomgr.c index 97b4ce5765..fdc9adf4af 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 29aa5e9601..24fee0596f 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/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c index e224de8534..cc680507ff 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,23 @@ 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); diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c index 9a69f53a5a..e86b5430b2 100644 --- a/src/core/security/client_auth_filter.c +++ b/src/core/security/client_auth_filter.c @@ -80,7 +80,7 @@ static void bubble_up_error(grpc_call_element *elem, const char *error_msg) { channel_data *chand = elem->channel_data; grpc_transport_stream_op_add_cancellation( &calld->op, GRPC_STATUS_UNAUTHENTICATED, - grpc_mdstr_from_string(chand->md_ctx, error_msg)); + grpc_mdstr_from_string(chand->md_ctx, error_msg, 0)); grpc_call_next_op(elem, &calld->op); } @@ -316,10 +316,10 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, (grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF( sc, "client_auth_filter"); chand->md_ctx = metadata_context; - chand->authority_string = grpc_mdstr_from_string(chand->md_ctx, ":authority"); - chand->path_string = grpc_mdstr_from_string(chand->md_ctx, ":path"); - chand->error_msg_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-message"); - chand->status_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-status"); + chand->authority_string = grpc_mdstr_from_string(chand->md_ctx, ":authority", 0); + chand->path_string = grpc_mdstr_from_string(chand->md_ctx, ":path", 0); + chand->error_msg_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-message", 0); + chand->status_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-status", 0); } /* Destructor for channel data */ diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index fb59fa4b0e..15268cefbe 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -259,8 +259,10 @@ static void ssl_build_config(const char *pem_root_certs, static void ssl_build_server_config( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, - size_t num_key_cert_pairs, grpc_ssl_server_config *config) { + size_t num_key_cert_pairs, int force_client_auth, + grpc_ssl_server_config *config) { size_t i; + config->force_client_auth = force_client_auth; if (pem_root_certs != NULL) { ssl_copy_key_material(pem_root_certs, &config->pem_root_certs, &config->pem_root_certs_size); @@ -302,20 +304,20 @@ grpc_credentials *grpc_ssl_credentials_create( 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) { + size_t num_key_cert_pairs, int force_client_auth) { grpc_ssl_server_credentials *c = gpr_malloc(sizeof(grpc_ssl_server_credentials)); memset(c, 0, sizeof(grpc_ssl_server_credentials)); c->base.type = GRPC_CREDENTIALS_TYPE_SSL; c->base.vtable = &ssl_server_vtable; ssl_build_server_config(pem_root_certs, pem_key_cert_pairs, - num_key_cert_pairs, &c->config); + num_key_cert_pairs, force_client_auth, &c->config); return &c->base; } /* -- 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 +330,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 +349,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 +403,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 +423,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 d988901cf7..8d40da47c1 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); @@ -188,7 +196,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 +249,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 833484310f..de1929fe76 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/core/security/security_connector.c b/src/core/security/security_connector.c index f6e423eb27..726b4c1e12 100644 --- a/src/core/security/security_connector.c +++ b/src/core/security/security_connector.c @@ -653,9 +653,10 @@ grpc_security_status grpc_ssl_server_security_connector_create( config->pem_private_keys_sizes, (const unsigned char **)config->pem_cert_chains, config->pem_cert_chains_sizes, config->num_key_cert_pairs, - config->pem_root_certs, config->pem_root_certs_size, ssl_cipher_suites(), - alpn_protocol_strings, alpn_protocol_string_lengths, - (uint16_t)num_alpn_protocols, &c->handshaker_factory); + config->pem_root_certs, config->pem_root_certs_size, + config->force_client_auth, ssl_cipher_suites(), alpn_protocol_strings, + alpn_protocol_string_lengths, (uint16_t)num_alpn_protocols, + &c->handshaker_factory); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", tsi_result_to_string(result)); diff --git a/src/core/security/security_connector.h b/src/core/security/security_connector.h index a4c723f026..2c9aa1c5a4 100644 --- a/src/core/security/security_connector.h +++ b/src/core/security/security_connector.h @@ -201,6 +201,7 @@ typedef struct { size_t num_key_cert_pairs; unsigned char *pem_root_certs; size_t pem_root_certs_size; + int force_client_auth; } grpc_ssl_server_config; /* Creates an SSL server_security_connector. diff --git a/src/core/support/stack_lockfree.c b/src/core/support/stack_lockfree.c index 2844330379..f24e272207 100644 --- a/src/core/support/stack_lockfree.c +++ b/src/core/support/stack_lockfree.c @@ -72,6 +72,11 @@ typedef union lockfree_node { struct gpr_stack_lockfree { lockfree_node *entries; lockfree_node head; /* An atomic entry describing curr head */ + +#ifndef NDEBUG + /* Bitmap of pushed entries to check for double-push or pop */ + gpr_atm pushed[(INVALID_ENTRY_INDEX+1)/(8*sizeof(gpr_atm))]; +#endif }; gpr_stack_lockfree *gpr_stack_lockfree_create(int entries) { @@ -86,6 +91,9 @@ gpr_stack_lockfree *gpr_stack_lockfree_create(int entries) { /* Clear out all entries */ memset(stack->entries, 0, entries * sizeof(stack->entries[0])); memset(&stack->head, 0, sizeof(stack->head)); +#ifndef NDEBUG + memset(&stack->pushed, 0, sizeof(stack->pushed)); +#endif /* Point the head at reserved dummy entry */ stack->head.contents.index = INVALID_ENTRY_INDEX; @@ -106,6 +114,19 @@ int gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) { /* Also post-increment the aba_ctr */ newhead.contents.aba_ctr = stack->entries[entry].contents.aba_ctr++; +#ifndef NDEBUG + /* Check for double push */ + { + int pushed_index = entry / (8*sizeof(gpr_atm)); + int pushed_bit = entry % (8*sizeof(gpr_atm)); + gpr_atm old_val; + + old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index], + (gpr_atm)(1UL << pushed_bit)); + GPR_ASSERT((old_val & (1UL<<pushed_bit)) == 0); + } +#endif + do { /* Atomically get the existing head value for use */ head.atm = gpr_atm_no_barrier_load(&(stack->head.atm)); @@ -119,6 +140,7 @@ int gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) { int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) { lockfree_node head; lockfree_node newhead; + do { head.atm = gpr_atm_acq_load(&(stack->head.atm)); if (head.contents.index == INVALID_ENTRY_INDEX) { @@ -128,5 +150,18 @@ int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) { gpr_atm_no_barrier_load(&(stack->entries[head.contents.index].atm)); } while (!gpr_atm_no_barrier_cas(&(stack->head.atm), head.atm, newhead.atm)); +#ifndef NDEBUG + /* Check for valid pop */ + { + int pushed_index = head.contents.index / (8*sizeof(gpr_atm)); + int pushed_bit = head.contents.index % (8*sizeof(gpr_atm)); + gpr_atm old_val; + + old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index], + -(gpr_atm)(1UL << pushed_bit)); + GPR_ASSERT((old_val & (1UL<<pushed_bit)) != 0); + } +#endif + return head.contents.index; } diff --git a/src/core/surface/call.c b/src/core/surface/call.c index aefcbad244..12378f0066 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -932,7 +932,7 @@ static int prepare_application_metadata(grpc_call *call, size_t count, GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data)); l->md = grpc_mdelem_from_string_and_buffer(call->metadata_context, md->key, (const gpr_uint8 *)md->value, - md->value_length); + md->value_length, 1); if (!grpc_mdstr_is_legal_header(l->md->key)) { gpr_log(GPR_ERROR, "attempt to send invalid metadata key"); return 0; @@ -1203,7 +1203,7 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call *c, static grpc_call_error cancel_with_status(grpc_call *c, grpc_status_code status, const char *description) { grpc_mdstr *details = - description ? grpc_mdstr_from_string(c->metadata_context, description) + description ? grpc_mdstr_from_string(c->metadata_context, description, 0) : NULL; GPR_ASSERT(status != GRPC_STATUS_OK); @@ -1373,7 +1373,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) { @@ -1496,7 +1497,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, op->data.send_status_from_server.status_details != NULL ? grpc_mdstr_from_string( call->metadata_context, - op->data.send_status_from_server.status_details) + op->data.send_status_from_server.status_details, 0) : NULL; req = &reqs[out++]; req->op = GRPC_IOREQ_SEND_CLOSE; diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c index 4052c65cc6..583d350128 100644 --- a/src/core/surface/channel.c +++ b/src/core/surface/channel.c @@ -101,19 +101,19 @@ grpc_channel *grpc_channel_create_from_filters( /* decremented by grpc_channel_destroy */ gpr_ref_init(&channel->refs, 1); channel->metadata_context = mdctx; - channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status"); + channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status", 0); channel->grpc_compression_algorithm_string = - grpc_mdstr_from_string(mdctx, "grpc-encoding"); - channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message"); + grpc_mdstr_from_string(mdctx, "grpc-encoding", 0); + channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message", 0); for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) { char buf[GPR_LTOA_MIN_BUFSIZE]; gpr_ltoa(i, buf); channel->grpc_status_elem[i] = grpc_mdelem_from_metadata_strings( mdctx, GRPC_MDSTR_REF(channel->grpc_status_string), - grpc_mdstr_from_string(mdctx, buf)); + grpc_mdstr_from_string(mdctx, buf, 0)); } - channel->path_string = grpc_mdstr_from_string(mdctx, ":path"); - channel->authority_string = grpc_mdstr_from_string(mdctx, ":authority"); + channel->path_string = grpc_mdstr_from_string(mdctx, ":path", 0); + channel->authority_string = grpc_mdstr_from_string(mdctx, ":authority", 0); gpr_mu_init(&channel->registered_call_mu); channel->registered_calls = NULL; @@ -167,10 +167,10 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel, channel, cq, grpc_mdelem_from_metadata_strings( channel->metadata_context, GRPC_MDSTR_REF(channel->path_string), - grpc_mdstr_from_string(channel->metadata_context, method)), + grpc_mdstr_from_string(channel->metadata_context, method, 0)), grpc_mdelem_from_metadata_strings( channel->metadata_context, GRPC_MDSTR_REF(channel->authority_string), - grpc_mdstr_from_string(channel->metadata_context, host)), + grpc_mdstr_from_string(channel->metadata_context, host, 0)), deadline); } @@ -179,10 +179,10 @@ void *grpc_channel_register_call(grpc_channel *channel, const char *method, registered_call *rc = gpr_malloc(sizeof(registered_call)); rc->path = grpc_mdelem_from_metadata_strings( channel->metadata_context, GRPC_MDSTR_REF(channel->path_string), - grpc_mdstr_from_string(channel->metadata_context, method)); + grpc_mdstr_from_string(channel->metadata_context, method, 0)); rc->authority = grpc_mdelem_from_metadata_strings( channel->metadata_context, GRPC_MDSTR_REF(channel->authority_string), - grpc_mdstr_from_string(channel->metadata_context, host)); + grpc_mdstr_from_string(channel->metadata_context, host, 0)); gpr_mu_lock(&channel->registered_call_mu); rc->next = channel->registered_calls; channel->registered_calls = rc; @@ -284,7 +284,7 @@ grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) { gpr_ltoa(i, tmp); return grpc_mdelem_from_metadata_strings( channel->metadata_context, GRPC_MDSTR_REF(channel->grpc_status_string), - grpc_mdstr_from_string(channel->metadata_context, tmp)); + grpc_mdstr_from_string(channel->metadata_context, tmp, 0)); } } diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c index fdc2185e14..707d615688 100644 --- a/src/core/surface/channel_create.c +++ b/src/core/surface/channel_create.c @@ -154,8 +154,8 @@ static const grpc_subchannel_factory_vtable subchannel_factory_vtable = { Asynchronously: - resolve target - connect to it (trying alternatives as presented) - perform handshakes */ -grpc_channel *grpc_channel_create(const char *target, - const grpc_channel_args *args) { +grpc_channel *grpc_insecure_channel_create(const char *target, + const grpc_channel_args *args) { grpc_channel *channel = NULL; #define MAX_FILTERS 3 const grpc_channel_filter *filters[MAX_FILTERS]; diff --git a/src/core/surface/server.c b/src/core/surface/server.c index 24f35298ef..f19bcbd090 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); @@ -530,6 +539,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 +549,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; @@ -677,8 +688,8 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, GPR_ASSERT(!is_last); chand->server = NULL; chand->channel = NULL; - chand->path_key = grpc_mdstr_from_string(metadata_context, ":path"); - chand->authority_key = grpc_mdstr_from_string(metadata_context, ":authority"); + chand->path_key = grpc_mdstr_from_string(metadata_context, ":path", 0); + chand->authority_key = grpc_mdstr_from_string(metadata_context, ":authority", 0); chand->next = chand->prev = chand; chand->registered_methods = NULL; chand->connectivity_state = GRPC_CHANNEL_IDLE; @@ -900,8 +911,8 @@ void grpc_server_setup_transport(grpc_server *s, grpc_transport *transport, chand->registered_methods = gpr_malloc(alloc); memset(chand->registered_methods, 0, alloc); for (rm = s->registered_methods; rm; rm = rm->next) { - host = rm->host ? grpc_mdstr_from_string(mdctx, rm->host) : NULL; - method = grpc_mdstr_from_string(mdctx, rm->method); + host = rm->host ? grpc_mdstr_from_string(mdctx, rm->host, 0) : NULL; + method = grpc_mdstr_from_string(mdctx, rm->method, 0); hash = GRPC_MDSTR_KV_HASH(host ? host->hash : 0, method->hash); for (probes = 0; chand->registered_methods[(hash + probes) % slots] .server_registered_method != NULL; diff --git a/src/core/transport/chttp2/frame_data.c b/src/core/transport/chttp2/frame_data.c index 7a4c355f23..40bf2ebd79 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 */ diff --git a/src/core/transport/chttp2/internal.h b/src/core/transport/chttp2/internal.h index e7901da510..f0eeb6de50 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 904b9afce7..d84960009b 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 */ @@ -607,7 +606,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/core/transport/chttp2/stream_encoder.c b/src/core/transport/chttp2/stream_encoder.c index 65b31a5afd..0f04169741 100644 --- a/src/core/transport/chttp2/stream_encoder.c +++ b/src/core/transport/chttp2/stream_encoder.c @@ -441,7 +441,7 @@ static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline, gpr_time_sub(deadline, gpr_now(deadline.clock_type)), timeout_str); mdelem = grpc_mdelem_from_metadata_strings( c->mdctx, GRPC_MDSTR_REF(c->timeout_key_str), - grpc_mdstr_from_string(c->mdctx, timeout_str)); + grpc_mdstr_from_string(c->mdctx, timeout_str, 0)); mdelem = hpack_enc(c, mdelem, st); if (mdelem) GRPC_MDELEM_UNREF(mdelem); } @@ -456,7 +456,7 @@ void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c, grpc_mdctx *ctx) { memset(c, 0, sizeof(*c)); c->mdctx = ctx; - c->timeout_key_str = grpc_mdstr_from_string(ctx, "grpc-timeout"); + c->timeout_key_str = grpc_mdstr_from_string(ctx, "grpc-timeout", 0); } void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) { diff --git a/src/core/transport/chttp2/stream_lists.c b/src/core/transport/chttp2/stream_lists.c index 590f6abfbc..9e68c1e146 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 d8ec117aa5..d39b0c42f7 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,50 +65,54 @@ 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, - 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; + GPR_ASSERT(!stream_global->writing_now); + + 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, @@ -118,6 +123,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); } } @@ -205,6 +215,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; @@ -216,9 +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); } + 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 50718da281..1ea4a82c16 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -232,7 +232,7 @@ static void init_transport(grpc_chttp2_transport *t, t->global.pings.next = t->global.pings.prev = &t->global.pings; t->parsing.is_client = is_client; t->parsing.str_grpc_timeout = - grpc_mdstr_from_string(t->metadata_context, "grpc-timeout"); + grpc_mdstr_from_string(t->metadata_context, "grpc-timeout", 0); t->parsing.deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0; t->writing.is_client = is_client; @@ -398,12 +398,16 @@ 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); + grpc_chttp2_list_remove_writable_stream(&t->global, &s->global); 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); @@ -581,8 +585,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 */ @@ -648,8 +650,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); } } @@ -766,6 +767,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) { @@ -847,6 +849,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 diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c index e95b7a21f9..967fd4898c 100644 --- a/src/core/transport/metadata.c +++ b/src/core/transport/metadata.c @@ -309,7 +309,37 @@ static void slice_unref(void *p) { unlock(ctx); } -grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str) { +grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str, int canonicalize_key) { + if (canonicalize_key) { + size_t len; + size_t i; + int canonical = 1; + + for (i = 0; str[i]; i++) { + if (str[i] >= 'A' && str[i] <= 'Z') { + canonical = 0; + /* Keep going in loop just to get string length */ + } + } + len = i; + + if (canonical) { + return grpc_mdstr_from_buffer(ctx, (const gpr_uint8 *)str, len); + } else { + char *copy = gpr_malloc(len); + grpc_mdstr *ret; + for (i = 0; i < len; i++) { + if (str[i] >= 'A' && str[i] <= 'Z') { + copy[i] = str[i] - 'A' + 'a'; + } else { + copy[i] = str[i]; + } + } + ret = grpc_mdstr_from_buffer(ctx, (const gpr_uint8 *)copy, len); + gpr_free(copy); + return ret; + } + } return grpc_mdstr_from_buffer(ctx, (const gpr_uint8 *)str, strlen(str)); } @@ -491,8 +521,8 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx, grpc_mdelem *grpc_mdelem_from_strings(grpc_mdctx *ctx, const char *key, const char *value) { return grpc_mdelem_from_metadata_strings(ctx, - grpc_mdstr_from_string(ctx, key), - grpc_mdstr_from_string(ctx, value)); + grpc_mdstr_from_string(ctx, key, 0), + grpc_mdstr_from_string(ctx, value, 0)); } grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key, @@ -504,9 +534,10 @@ grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key, grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx, const char *key, const gpr_uint8 *value, - size_t value_length) { + size_t value_length, + int canonicalize_key) { return grpc_mdelem_from_metadata_strings( - ctx, grpc_mdstr_from_string(ctx, key), + ctx, grpc_mdstr_from_string(ctx, key, canonicalize_key), grpc_mdstr_from_buffer(ctx, value, value_length)); } diff --git a/src/core/transport/metadata.h b/src/core/transport/metadata.h index 99b15322c3..15ef9bb555 100644 --- a/src/core/transport/metadata.h +++ b/src/core/transport/metadata.h @@ -95,7 +95,7 @@ size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *mdctx); /* Constructors for grpc_mdstr instances; take a variety of data types that clients may have handy */ -grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str); +grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str, int perform_key_canonicalization); /* Unrefs the slice. */ grpc_mdstr *grpc_mdstr_from_slice(grpc_mdctx *ctx, gpr_slice slice); grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *str, @@ -117,7 +117,8 @@ grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key, grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx, const char *key, const gpr_uint8 *value, - size_t value_length); + size_t value_length, + int canonicalize_key); /* Mutator and accessor for grpc_mdelem user data. The destructor function is used as a type tag and is checked during user_data fetch. */ diff --git a/src/core/transport/transport_op_string.c b/src/core/transport/transport_op_string.c index 10d796fc15..f62c340e97 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); } diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c index 6156a39d09..609fc06ed5 100644 --- a/src/core/tsi/ssl_transport_security.c +++ b/src/core/tsi/ssl_transport_security.c @@ -1293,8 +1293,8 @@ tsi_result tsi_create_ssl_server_handshaker_factory( const size_t* pem_private_keys_sizes, const unsigned char** pem_cert_chains, const size_t* pem_cert_chains_sizes, size_t key_cert_pair_count, const unsigned char* pem_client_root_certs, - size_t pem_client_root_certs_size, const char* cipher_list, - const unsigned char** alpn_protocols, + size_t pem_client_root_certs_size, int force_client_auth, + const char* cipher_list, const unsigned char** alpn_protocols, const unsigned char* alpn_protocols_lengths, uint16_t num_alpn_protocols, tsi_ssl_handshaker_factory** factory) { tsi_ssl_server_handshaker_factory* impl = NULL; @@ -1349,6 +1349,7 @@ tsi_result tsi_create_ssl_server_handshaker_factory( if (result != TSI_OK) break; if (pem_client_root_certs != NULL) { + int flags = SSL_VERIFY_PEER; STACK_OF(X509_NAME)* root_names = NULL; result = ssl_ctx_load_verification_certs( impl->ssl_contexts[i], pem_client_root_certs, @@ -1358,7 +1359,8 @@ tsi_result tsi_create_ssl_server_handshaker_factory( break; } SSL_CTX_set_client_CA_list(impl->ssl_contexts[i], root_names); - SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER, NULL); + if (force_client_auth) flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + SSL_CTX_set_verify(impl->ssl_contexts[i], flags, NULL); /* TODO(jboeuf): Add revocation verification. */ } diff --git a/src/core/tsi/ssl_transport_security.h b/src/core/tsi/ssl_transport_security.h index b2aa2f393e..4bf6c81b75 100644 --- a/src/core/tsi/ssl_transport_security.h +++ b/src/core/tsi/ssl_transport_security.h @@ -107,10 +107,14 @@ tsi_result tsi_create_ssl_client_handshaker_factory( - key_cert_pair_count indicates the number of items in the private_key_files and cert_chain_files parameters. - pem_client_roots is the buffer containing the PEM encoding of the client - root certificates. This parameter may be NULL in which case the server - will not ask the client to authenticate itself with a certificate (server- - only authentication mode). - - pem_client_roots_size is the size of the associated buffer. + root certificates. This parameter may be NULL in which case the server will + not authenticate the client. If not NULL, the force_client_auth parameter + specifies if the server will accept only authenticated clients or both + authenticated and non-authenticated clients. + - pem_client_root_certs_size is the size of the associated buffer. + - force_client_auth, if set to non-zero will force the client to authenticate + with an SSL cert. Note that this option is ignored if pem_client_root_certs + is NULL or pem_client_roots_certs_size is 0 - cipher_suites contains an optional list of the ciphers that the server supports. The format of this string is described in: https://www.openssl.org/docs/apps/ciphers.html. @@ -131,8 +135,8 @@ tsi_result tsi_create_ssl_server_handshaker_factory( const size_t* pem_private_keys_sizes, const unsigned char** pem_cert_chains, const size_t* pem_cert_chains_sizes, size_t key_cert_pair_count, const unsigned char* pem_client_root_certs, - size_t pem_client_root_certs_size, const char* cipher_suites, - const unsigned char** alpn_protocols, + size_t pem_client_root_certs_size, int force_client_auth, + const char* cipher_suites, const unsigned char** alpn_protocols, const unsigned char* alpn_protocols_lengths, uint16_t num_alpn_protocols, tsi_ssl_handshaker_factory** factory); diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc index 5ad8784567..e802fa8034 100644 --- a/src/cpp/client/insecure_credentials.cc +++ b/src/cpp/client/insecure_credentials.cc @@ -49,7 +49,7 @@ class InsecureCredentialsImpl GRPC_FINAL : public Credentials { grpc_channel_args channel_args; args.SetChannelArgs(&channel_args); return std::shared_ptr<ChannelInterface>(new Channel( - target, grpc_channel_create(target.c_str(), &channel_args))); + target, grpc_insecure_channel_create(target.c_str(), &channel_args))); } // InsecureCredentials should not be applied to a call. diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc index 01c7f14f1a..abf0cb387e 100644 --- a/src/cpp/client/secure_credentials.cc +++ b/src/cpp/client/secure_credentials.cc @@ -99,8 +99,8 @@ std::shared_ptr<Credentials> ServiceAccountCredentials( } // Builds JWT credentials. -std::shared_ptr<Credentials> JWTCredentials(const grpc::string& json_key, - long token_lifetime_seconds) { +std::shared_ptr<Credentials> 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<Credentials> 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/cpp/server/create_default_thread_pool.cc b/src/cpp/server/create_default_thread_pool.cc index cc182f59f4..81c84474d8 100644 --- a/src/cpp/server/create_default_thread_pool.cc +++ b/src/cpp/server/create_default_thread_pool.cc @@ -32,7 +32,7 @@ */ #include <grpc/support/cpu.h> -#include <grpc++/fixed_size_thread_pool.h> +#include <grpc++/dynamic_thread_pool.h> #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/src/cpp/server/dynamic_thread_pool.cc b/src/cpp/server/dynamic_thread_pool.cc new file mode 100644 index 0000000000..f58d0420df --- /dev/null +++ b/src/cpp/server/dynamic_thread_pool.cc @@ -0,0 +1,131 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <grpc++/impl/sync.h> +#include <grpc++/impl/thd.h> +#include <grpc++/dynamic_thread_pool.h> + +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<grpc::mutex> lock(pool_->mu_); + pool_->nthreads_--; + // Move ourselves to dead list + pool_->dead_threads_.push_back(this); + + if ((pool_->shutdown_) && (pool_->nthreads_ == 0)) { + pool_->shutdown_cv_.notify_one(); + } +} + +void DynamicThreadPool::ThreadFunc() { + for (;;) { + // Wait until work is available or we are shutting down. + grpc::unique_lock<grpc::mutex> 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), nthreads_(0), + threads_waiting_(0) { + for (int i = 0; i < reserve_threads_; i++) { + grpc::lock_guard<grpc::mutex> lock(mu_); + nthreads_++; + new DynamicThread(this); + } +} + +void DynamicThreadPool::ReapThreads(std::list<DynamicThread*>* tlist) { + for (auto t = tlist->begin(); t != tlist->end(); t = tlist->erase(t)) { + delete *t; + } +} + +DynamicThreadPool::~DynamicThreadPool() { + grpc::unique_lock<grpc::mutex> lock(mu_); + shutdown_ = true; + cv_.notify_all(); + while (nthreads_ != 0) { + shutdown_cv_.wait(lock); + } + ReapThreads(&dead_threads_); +} + +void DynamicThreadPool::Add(const std::function<void()>& callback) { + grpc::lock_guard<grpc::mutex> 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_++; + new DynamicThread(this); + } else { + cv_.notify_one(); + } + // Also use this chance to harvest dead threads + if (!dead_threads_.empty()) { + ReapThreads(&dead_threads_); + } +} + +} // namespace grpc diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc index 3e262dd74f..32c45e2280 100644 --- a/src/cpp/server/secure_server_credentials.cc +++ b/src/cpp/server/secure_server_credentials.cc @@ -51,7 +51,8 @@ std::shared_ptr<ServerCredentials> SslServerCredentials( } grpc_server_credentials* c_creds = grpc_ssl_server_credentials_create( options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(), - &pem_key_cert_pairs[0], pem_key_cert_pairs.size()); + &pem_key_cert_pairs[0], pem_key_cert_pairs.size(), + options.force_client_auth); return std::shared_ptr<ServerCredentials>( new SecureServerCredentials(c_creds)); } diff --git a/src/cpp/util/time.cc b/src/cpp/util/time.cc index a814cad452..799c597e0b 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<system_clock::time_point::duration>(seconds(t.tv_sec)); tp += diff --git a/src/csharp/Grpc.Auth/GoogleCredential.cs b/src/csharp/Grpc.Auth/GoogleCredential.cs index 7edf19ed67..9936cf583c 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>(); - string privateKeyString = o1.GetValue(PrivateKeyFieldName).Value<string>(); - var privateKey = ParsePrivateKeyFromString(privateKeyString); + JObject jsonCredentialParameters = JObject.Parse(File.ReadAllText(credsPath)); + string clientEmail = jsonCredentialParameters.GetValue(ClientEmailFieldName).Value<string>(); + string privateKeyString = jsonCredentialParameters.GetValue(PrivateKeyFieldName).Value<string>(); 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 fdec2e7bd7..8e5036832d 100644 --- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj +++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj @@ -11,6 +11,7 @@ <AssemblyName>Grpc.Auth</AssemblyName> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <DocumentationFile>bin\$(Configuration)\Grpc.Auth.Xml</DocumentationFile> + <NuGetPackageImportStamp>9b408026</NuGetPackageImportStamp> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> @@ -23,25 +24,37 @@ <ConsolePause>false</ConsolePause> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <DebugType>full</DebugType> + <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release</OutputPath> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> <ConsolePause>false</ConsolePause> </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\ReleaseSigned</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <SignAssembly>True</SignAssembly> + <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile> + </PropertyGroup> <ItemGroup> <Reference Include="BouncyCastle.Crypto"> <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath> </Reference> - <Reference Include="Google.Apis.Auth"> - <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.dll</HintPath> + <Reference Include="Google.Apis.Auth, Version=1.9.2.27817, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.dll</HintPath> </Reference> - <Reference Include="Google.Apis.Auth.PlatformServices"> - <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath> + <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.2.27820, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath> </Reference> - <Reference Include="Google.Apis.Core"> - <HintPath>..\packages\Google.Apis.Core.1.9.1\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath> + <Reference Include="Google.Apis.Core, Version=1.9.2.27816, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\Google.Apis.Core.1.9.2\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath> </Reference> <Reference Include="Microsoft.Threading.Tasks"> <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath> @@ -52,18 +65,20 @@ <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop"> <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath> </Reference> - <Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> + <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll</HintPath> + <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> </Reference> <Reference Include="System" /> <Reference Include="System.Net" /> <Reference Include="System.Net.Http" /> - <Reference Include="System.Net.Http.Extensions"> - <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll</HintPath> + <Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath> </Reference> - <Reference Include="System.Net.Http.Primitives"> - <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll</HintPath> + <Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath> </Reference> <Reference Include="System.Net.Http.WebRequest" /> </ItemGroup> @@ -73,7 +88,7 @@ </Compile> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="GoogleCredential.cs" /> - <Compile Include="OAuth2InterceptorFactory.cs" /> + <Compile Include="OAuth2Interceptors.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <ItemGroup> @@ -87,9 +102,11 @@ <None Include="Grpc.Auth.nuspec" /> <None Include="packages.config" /> </ItemGroup> - <Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" /> - <Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''"> - <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" /> - <Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" /> + <Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" /> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" /> </Target> </Project>
\ No newline at end of file diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec index 1262bdbdab..2dc10d24c2 100644 --- a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec +++ b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec @@ -15,15 +15,14 @@ <copyright>Copyright 2015, Google Inc.</copyright> <tags>gRPC RPC Protocol HTTP/2 Auth OAuth2</tags> <dependencies> - <dependency id="BouncyCastle" version="1.7.0" /> - <dependency id="Google.Apis.Auth" version="1.9.1" /> + <dependency id="Google.Apis.Auth" version="1.9.2" /> <dependency id="Grpc.Core" version="$version$" /> </dependencies> </metadata> <files> - <file src="bin/Release/Grpc.Auth.dll" target="lib/net45" /> - <file src="bin/Release/Grpc.Auth.pdb" target="lib/net45" /> - <file src="bin/Release/Grpc.Auth.xml" target="lib/net45" /> + <file src="bin/ReleaseSigned/Grpc.Auth.dll" target="lib/net45" /> + <file src="bin/ReleaseSigned/Grpc.Auth.pdb" target="lib/net45" /> + <file src="bin/ReleaseSigned/Grpc.Auth.xml" target="lib/net45" /> <file src="**\*.cs" target="src" /> </files> </package> diff --git a/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs b/src/csharp/Grpc.Auth/OAuth2Interceptors.cs index 420c4cb537..c785ca5a16 100644 --- a/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs +++ b/src/csharp/Grpc.Auth/OAuth2Interceptors.cs @@ -47,18 +47,32 @@ using Grpc.Core.Utils; namespace Grpc.Auth { - public static class OAuth2InterceptorFactory + public static class OAuth2Interceptors { /// <summary> - /// Creates OAuth2 interceptor. + /// Creates OAuth2 interceptor that will obtain access token from GoogleCredentials. /// </summary> - public static MetadataInterceptorDelegate Create(GoogleCredential googleCredential) + public static MetadataInterceptorDelegate FromCredential(GoogleCredential googleCredential) { var interceptor = new OAuth2Interceptor(googleCredential.InternalCredential, SystemClock.Default); return new MetadataInterceptorDelegate(interceptor.InterceptHeaders); } /// <summary> + /// Creates OAuth2 interceptor that will use given OAuth2 token. + /// </summary> + /// <param name="oauth2Token"></param> + /// <returns></returns> + public static MetadataInterceptorDelegate FromAccessToken(string oauth2Token) + { + Preconditions.CheckNotNull(oauth2Token); + return new MetadataInterceptorDelegate((metadata) => + { + metadata.Add(OAuth2Interceptor.CreateBearerTokenHeader(oauth2Token)); + }); + } + + /// <summary> /// Injects OAuth2 authorization header into initial metadata (= request headers). /// </summary> private class OAuth2Interceptor @@ -97,8 +111,15 @@ namespace Grpc.Auth public void InterceptHeaders(Metadata metadata) { var accessToken = GetAccessToken(CancellationToken.None); - metadata.Add(new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken)); + metadata.Add(CreateBearerTokenHeader(accessToken)); + } + + public static Metadata.Entry CreateBearerTokenHeader(string accessToken) + { + return new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken); } } + + } } diff --git a/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs index 70cb32d5b2..83396c546b 100644 --- a/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs +++ b/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs @@ -9,5 +9,3 @@ using System.Runtime.CompilerServices; [assembly: AssemblyCopyright("Google Inc. All rights reserved.")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] - -[assembly: InternalsVisibleTo("Grpc.Auth.Tests")] diff --git a/src/csharp/Grpc.Auth/app.config b/src/csharp/Grpc.Auth/app.config index 966b777192..0a82bb4f16 100644 --- a/src/csharp/Grpc.Auth/app.config +++ b/src/csharp/Grpc.Auth/app.config @@ -4,7 +4,7 @@ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" /> + <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> diff --git a/src/csharp/Grpc.Auth/packages.config b/src/csharp/Grpc.Auth/packages.config index 7d348872ba..29be953bf3 100644 --- a/src/csharp/Grpc.Auth/packages.config +++ b/src/csharp/Grpc.Auth/packages.config @@ -1,11 +1,11 @@ <?xml version="1.0" encoding="utf-8"?> <packages> <package id="BouncyCastle" version="1.7.0" targetFramework="net45" /> - <package id="Google.Apis.Auth" version="1.9.1" targetFramework="net45" /> - <package id="Google.Apis.Core" version="1.9.1" targetFramework="net45" /> - <package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" /> + <package id="Google.Apis.Auth" version="1.9.2" targetFramework="net45" /> + <package id="Google.Apis.Core" version="1.9.2" targetFramework="net45" /> + <package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" /> <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" /> - <package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" /> - <package id="Microsoft.Net.Http" version="2.2.28" targetFramework="net45" /> - <package id="Newtonsoft.Json" version="6.0.6" targetFramework="net45" /> + <package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" /> + <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" /> + <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" /> </packages>
\ No newline at end of file diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs index 8ba2c8a9a2..540fe756c0 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<string, string> EchoMethod = new Method<string, string>( @@ -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] @@ -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<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty); + try { - var internalCall = new Call<string, string>(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<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty); - var call = Calls.AsyncClientStreamingCall(internalCall, CancellationToken.None); + var internalCall = new Call<string, string>(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<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty); + var internalCall = new Call<string, string>(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] @@ -218,8 +209,8 @@ namespace Grpc.Core.Tests { var headers = new Metadata { - new Metadata.Entry("asciiHeader", "abcdefg"), - new Metadata.Entry("binaryHeader-bin", new byte[] { 1, 2, 3, 0, 0xff }), + new Metadata.Entry("ascii-header", "abcdefg"), + new Metadata.Entry("binary-header-bin", new byte[] { 1, 2, 3, 0, 0xff }), }; var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, headers); var call = Calls.AsyncUnaryCall(internalCall, "ABC", CancellationToken.None); @@ -277,6 +268,14 @@ namespace Grpc.Core.Tests Assert.IsTrue(userAgent.StartsWith("grpc-csharp/")); } + [Test] + public void PeerInfoPresent() + { + var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty); + string peer = Calls.BlockingUnaryCall(internalCall, "RETURN-PEER", CancellationToken.None); + Assert.IsTrue(peer.Contains(Host)); + } + private static async Task<string> EchoHandler(string request, ServerCallContext context) { foreach (Metadata.Entry metadataEntry in context.RequestHeaders) @@ -292,6 +291,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.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj index 927954c448..242a60d098 100644 --- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj +++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj @@ -17,20 +17,43 @@ <DefineConstants>DEBUG;</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <ConsolePause>false</ConsolePause> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <DebugType>full</DebugType> + <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release</OutputPath> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <ConsolePause>false</ConsolePause> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\ReleaseSigned</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <SignAssembly>True</SignAssembly> + <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile> </PropertyGroup> <ItemGroup> + <Reference Include="nunit.core"> + <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll</HintPath> + <Private>False</Private> + </Reference> + <Reference Include="nunit.core.interfaces"> + <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll</HintPath> + <Private>False</Private> + </Reference> <Reference Include="nunit.framework"> <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath> </Reference> + <Reference Include="nunit.util"> + <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll</HintPath> + <Private>False</Private> + </Reference> + <Reference Include="NUnit.VisualStudio.TestAdapter"> + <HintPath>..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll</HintPath> + <Private>False</Private> + </Reference> <Reference Include="System" /> <Reference Include="System.Interactive.Async"> <HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath> @@ -44,13 +67,15 @@ <Compile Include="ClientServerTest.cs" /> <Compile Include="ServerTest.cs" /> <Compile Include="GrpcEnvironmentTest.cs" /> - <Compile Include="TimespecTest.cs" /> <Compile Include="PInvokeTest.cs" /> <Compile Include="Internal\MetadataArraySafeHandleTest.cs" /> <Compile Include="Internal\CompletionQueueSafeHandleTest.cs" /> <Compile Include="Internal\CompletionQueueEventTest.cs" /> <Compile Include="Internal\ChannelArgsSafeHandleTest.cs" /> <Compile Include="ChannelOptionsTest.cs" /> + <Compile Include="Internal\TimespecTest.cs" /> + <Compile Include="TimeoutsTest.cs" /> + <Compile Include="NUnitVersionTest.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <ItemGroup> @@ -60,7 +85,9 @@ </ProjectReference> </ItemGroup> <ItemGroup> - <None Include="packages.config" /> + <None Include="packages.config"> + <SubType>Designer</SubType> + </None> </ItemGroup> <ItemGroup> <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> 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 0000000000..874df02baa --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs @@ -0,0 +1,202 @@ +#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_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] + 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()); + + // 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()); + + // Illegal inputs + 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_Overflow() + { + // 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_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 + // 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"); + } + } + + [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, 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 + { + Console.WriteLine("Test cannot be run on this platform, skipping the test."); + } + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs b/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs new file mode 100644 index 0000000000..600df1a18d --- /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 +{ + /// <summary> + /// Tests if the version of nunit-console used is sufficient to run async tests. + /// </summary> + 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/src/csharp/Grpc.Core.Tests/ServerTest.cs b/src/csharp/Grpc.Core.Tests/ServerTest.cs index 1119aa370e..ba9efae871 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 new file mode 100644 index 0000000000..010ffd898a --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs @@ -0,0 +1,207 @@ +#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 +{ + /// <summary> + /// Tests for Deadline support. + /// </summary> + public class TimeoutsTest + { + const string Host = "localhost"; + const string ServiceName = "/tests.Test"; + + static readonly Method<string, string> TestMethod = new Method<string, string>( + 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<string> stringFromServerHandlerTcs; + + Server server; + Channel channel; + + [SetUp] + public void Init() + { + server = new Server(); + server.AddServiceDefinition(ServiceDefinition); + int port = server.AddPort(Host, Server.PickUnusedPort, ServerCredentials.Insecure); + server.Start(); + channel = new Channel(Host, port, Credentials.Insecure); + + stringFromServerHandlerTcs = new TaskCompletionSource<string>(); + } + + [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<string, string>(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<string, string>(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<string, string>(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 DeadlineInThePast() + { + var deadline = DateTime.MinValue; + var internalCall = new Call<string, string>(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() + { + var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)); + var internalCall = new Call<string, string>(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() + { + var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)); + var internalCall = new Call<string, string>(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<string> 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<object>(); + context.CancellationToken.Register(() => { tcs.SetResult(null); }); + await tcs.Task; + stringFromServerHandlerTcs.SetResult("CANCELLED"); + return ""; + } + + return ""; + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/TimespecTest.cs b/src/csharp/Grpc.Core.Tests/TimespecTest.cs deleted file mode 100644 index a34b407a01..0000000000 --- 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.Tests/packages.config b/src/csharp/Grpc.Core.Tests/packages.config index 28af8d78c6..62077f41be 100644 --- a/src/csharp/Grpc.Core.Tests/packages.config +++ b/src/csharp/Grpc.Core.Tests/packages.config @@ -2,4 +2,5 @@ <packages> <package id="Ix-Async" version="1.2.3" targetFramework="net45" /> <package id="NUnit" version="2.6.4" targetFramework="net45" /> + <package id="NUnitTestAdapter" version="2.0.0" targetFramework="net45" /> </packages>
\ No newline at end of file diff --git a/src/csharp/Grpc.Core/Call.cs b/src/csharp/Grpc.Core/Call.cs index 37b452f020..94c5e26082 100644 --- a/src/csharp/Grpc.Core/Call.cs +++ b/src/csharp/Grpc.Core/Call.cs @@ -47,14 +47,21 @@ namespace Grpc.Core readonly Marshaller<TResponse> responseMarshaller; readonly Channel channel; readonly Metadata headers; + readonly DateTime deadline; public Call(string serviceName, Method<TRequest, TResponse> method, Channel channel, Metadata headers) + : this(serviceName, method, channel, headers, DateTime.MaxValue) + { + } + + public Call(string serviceName, Method<TRequest, TResponse> 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<TRequest> RequestMarshaller { get diff --git a/src/csharp/Grpc.Core/Calls.cs b/src/csharp/Grpc.Core/Calls.cs index 359fe53741..054fc27491 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<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); // TODO(jtattermusch): this gives a race that cancellation can be requested before the call even starts. RegisterCancellationCallback(asyncCall, token); - return asyncCall.UnaryCall(call.Channel, call.Name, req, call.Headers); + return asyncCall.UnaryCall(call.Channel, call.Name, req, call.Headers, call.Deadline); } public static AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token) @@ -58,8 +58,8 @@ namespace Grpc.Core where TResponse : class { var asyncCall = new AsyncCall<TRequest, TResponse>(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<TResponse>(asyncResult, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); } @@ -69,8 +69,8 @@ namespace Grpc.Core where TResponse : class { var asyncCall = new AsyncCall<TRequest, TResponse>(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<TRequest, TResponse>(asyncCall); return new AsyncServerStreamingCall<TResponse>(responseStream, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); @@ -81,8 +81,8 @@ namespace Grpc.Core where TResponse : class { var asyncCall = new AsyncCall<TRequest, TResponse>(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<TRequest, TResponse>(asyncCall); return new AsyncClientStreamingCall<TRequest, TResponse>(requestStream, resultTask, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); @@ -93,8 +93,8 @@ namespace Grpc.Core where TResponse : class { var asyncCall = new AsyncCall<TRequest, TResponse>(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<TRequest, TResponse>(asyncCall); var responseStream = new ClientResponseStream<TRequest, TResponse>(asyncCall); diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs index e5c6abd2cb..18e6f2fda5 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. /// </summary> /// <param name="host">The DNS name of IP address of the host.</param> - /// <param name="credentials">Optional credentials to create a secure channel.</param> + /// <param name="credentials">Credentials to secure the channel.</param> /// <param name="options">Channel options.</param> - public Channel(string host, Credentials credentials = null, IEnumerable<ChannelOption> options = null) + public Channel(string host, Credentials credentials, IEnumerable<ChannelOption> options = null) { this.environment = GrpcEnvironment.GetInstance(); this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>(); 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 /// </summary> /// <param name="host">DNS name or IP address</param> /// <param name="port">the port</param> - /// <param name="credentials">Optional credentials to create a secure channel.</param> + /// <param name="credentials">Credentials to secure the channel.</param> /// <param name="options">Channel options.</param> - public Channel(string host, int port, Credentials credentials = null, IEnumerable<ChannelOption> options = null) : + public Channel(string host, int port, Credentials credentials, IEnumerable<ChannelOption> options = null) : this(string.Format("{0}:{1}", host, port), credentials, options) { } diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs index a099f96aea..fd3473128a 100644 --- a/src/csharp/Grpc.Core/ClientBase.cs +++ b/src/csharp/Grpc.Core/ClientBase.cs @@ -76,7 +76,7 @@ namespace Grpc.Core /// <summary> /// Creates a new call to given method. /// </summary> - protected Call<TRequest, TResponse> CreateCall<TRequest, TResponse>(string serviceName, Method<TRequest, TResponse> method, Metadata metadata) + protected Call<TRequest, TResponse> CreateCall<TRequest, TResponse>(string serviceName, Method<TRequest, TResponse> 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<TRequest, TResponse>(serviceName, method, channel, metadata); + return new Call<TRequest, TResponse>(serviceName, method, channel, + metadata ?? Metadata.Empty, deadline ?? DateTime.MaxValue); } } } diff --git a/src/csharp/Grpc.Core/Credentials.cs b/src/csharp/Grpc.Core/Credentials.cs index e64c1e3dc1..4fcac0c4c0 100644 --- a/src/csharp/Grpc.Core/Credentials.cs +++ b/src/csharp/Grpc.Core/Credentials.cs @@ -41,39 +41,98 @@ namespace Grpc.Core /// </summary> public abstract class Credentials { + static readonly Credentials InsecureInstance = new InsecureCredentialsImpl(); + + /// <summary> + /// Returns instance of credential that provides no security and + /// will result in creating an unsecure channel with no encryption whatsoever. + /// </summary> + public static Credentials Insecure + { + get + { + return InsecureInstance; + } + } + /// <summary> - /// Creates native object for the credentials. + /// Creates native object for the credentials. May return null if insecure channel + /// should be created. /// </summary> /// <returns>The native credentials.</returns> internal abstract CredentialsSafeHandle ToNativeCredentials(); + + private sealed class InsecureCredentialsImpl : Credentials + { + internal override CredentialsSafeHandle ToNativeCredentials() + { + return null; + } + } } /// <summary> /// Client-side SSL credentials. /// </summary> - public class SslCredentials : Credentials + public sealed class SslCredentials : Credentials { - string pemRootCerts; + readonly string rootCertificates; + readonly KeyCertificatePair keyCertificatePair; - public SslCredentials(string pemRootCerts) + /// <summary> + /// 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. + /// </summary> + public SslCredentials() : this(null, null) { - this.pemRootCerts = pemRootCerts; + } + + /// <summary> + /// Creates client-side SSL credentials from + /// a string containing PEM encoded root certificates. + /// </summary> + public SslCredentials(string rootCertificates) : this(rootCertificates, null) + { + } + + /// <summary> + /// Creates client-side SSL credentials. + /// </summary> + /// <param name="rootCertificates">string containing PEM encoded server root certificates.</param> + /// <param name="keyCertificatePair">a key certificate pair.</param> + public SslCredentials(string rootCertificates, KeyCertificatePair keyCertificatePair) + { + this.rootCertificates = rootCertificates; + this.keyCertificatePair = keyCertificatePair; } /// <summary> /// PEM encoding of the server root certificates. /// </summary> - public string RootCerts + public string RootCertificates + { + get + { + return this.rootCertificates; + } + } + + /// <summary> + /// Client side key and certificate pair. + /// If null, client will not use key and certificate pair. + /// </summary> + 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 fd68b91851..940a6b8ac0 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -21,15 +21,23 @@ <DefineConstants>DEBUG;</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <ConsolePause>false</ConsolePause> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <DebugType>full</DebugType> + <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release</OutputPath> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <ConsolePause>false</ConsolePause> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\ReleaseSigned</OutputPath> + <DefineConstants>SIGNED</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <SignAssembly>True</SignAssembly> + <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile> </PropertyGroup> <ItemGroup> <Reference Include="System" /> @@ -47,7 +55,6 @@ <Compile Include="IServerStreamWriter.cs" /> <Compile Include="IAsyncStreamWriter.cs" /> <Compile Include="IAsyncStreamReader.cs" /> - <Compile Include="Internal\GrpcLog.cs" /> <Compile Include="Version.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="RpcException.cs" /> @@ -103,6 +110,11 @@ <Compile Include="ChannelOptions.cs" /> <Compile Include="AsyncUnaryCall.cs" /> <Compile Include="VersionInfo.cs" /> + <Compile Include="Internal\CStringSafeHandle.cs" /> + <Compile Include="KeyCertificatePair.cs" /> + <Compile Include="Logging\ILogger.cs" /> + <Compile Include="Logging\ConsoleLogger.cs" /> + <Compile Include="Internal\NativeLogRedirector.cs" /> </ItemGroup> <ItemGroup> <None Include="Grpc.Core.nuspec" /> @@ -133,4 +145,7 @@ </Target> <Import Project="..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets')" /> <Import Project="..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets')" /> + <ItemGroup> + <Folder Include="Logging\" /> + </ItemGroup> </Project>
\ No newline at end of file diff --git a/src/csharp/Grpc.Core/Grpc.Core.nuspec b/src/csharp/Grpc.Core/Grpc.Core.nuspec index 5ace6dcf89..086776f69d 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.nuspec +++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec @@ -21,9 +21,9 @@ </dependencies> </metadata> <files> - <file src="bin/Release/Grpc.Core.dll" target="lib/net45" /> - <file src="bin/Release/Grpc.Core.pdb" target="lib/net45" /> - <file src="bin/Release/Grpc.Core.xml" target="lib/net45" /> + <file src="bin/ReleaseSigned/Grpc.Core.dll" target="lib/net45" /> + <file src="bin/ReleaseSigned/Grpc.Core.pdb" target="lib/net45" /> + <file src="bin/ReleaseSigned/Grpc.Core.xml" target="lib/net45" /> <file src="**\*.cs" target="src" /> </files> </package> diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs index 47d1651aab..034a66be3c 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(); @@ -93,17 +96,38 @@ namespace Grpc.Core } /// <summary> + /// Gets application-wide logger used by gRPC. + /// </summary> + /// <value>The logger.</value> + public static ILogger Logger + { + get + { + return logger; + } + } + + /// <summary> + /// Sets the application-wide logger that should be used by gRPC. + /// </summary> + public static void SetLogger(ILogger customLogger) + { + Preconditions.CheckNotNull(customLogger); + logger = customLogger; + } + + /// <summary> /// Creates gRPC environment. /// </summary> 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."); } /// <summary> @@ -154,8 +178,7 @@ namespace Grpc.Core debugStats.CheckOK(); - // TODO: use proper logging here - Console.WriteLine("GRPC shutdown."); + Logger.Info("gRPC shutdown."); } /// <summary> @@ -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 f983dbb759..bfcb9366a1 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 /// </summary> internal class AsyncCall<TRequest, TResponse> : AsyncCallBase<TRequest, TResponse> { + static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<AsyncCall<TRequest, TResponse>>(); + Channel channel; // Completion of a pending unary response if not null. @@ -61,10 +64,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 +79,7 @@ namespace Grpc.Core.Internal /// <summary> /// Blocking unary request - unary response call. /// </summary> - 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 +89,7 @@ namespace Grpc.Core.Internal lock (myLock) { - Initialize(channel, cq, methodName); + Initialize(channel, cq, methodName, Timespec.FromDateTime(deadline)); started = true; halfcloseRequested = true; readingDone = true; @@ -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."); } } } @@ -126,7 +129,7 @@ namespace Grpc.Core.Internal /// <summary> /// Starts a unary request - unary response call. /// </summary> - public Task<TResponse> UnaryCallAsync(TRequest msg, Metadata headers) + public Task<TResponse> UnaryCallAsync(TRequest msg, Metadata headers, DateTime deadline) { lock (myLock) { @@ -151,7 +154,7 @@ namespace Grpc.Core.Internal /// Starts a streamed request - unary response call. /// Use StartSendMessage and StartSendCloseFromClient to stream requests. /// </summary> - public Task<TResponse> ClientStreamingCallAsync(Metadata headers) + public Task<TResponse> ClientStreamingCallAsync(Metadata headers, DateTime deadline) { lock (myLock) { @@ -173,7 +176,7 @@ namespace Grpc.Core.Internal /// <summary> /// Starts a unary request - streamed response call. /// </summary> - public void StartServerStreamingCall(TRequest msg, Metadata headers) + public void StartServerStreamingCall(TRequest msg, Metadata headers, DateTime deadline) { lock (myLock) { @@ -196,7 +199,7 @@ namespace Grpc.Core.Internal /// Starts a streaming request - streaming response call. /// Use StartSendMessage and StartSendCloseFromClient to stream requests. /// </summary> - public void StartDuplexStreamingCall(Metadata headers) + public void StartDuplexStreamingCall(Metadata headers, DateTime deadline) { lock (myLock) { diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs index 64713c8c52..38f2a5baeb 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 /// </summary> internal abstract class AsyncCallBase<TWrite, TRead> { + static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<AsyncCallBase<TWrite, TRead>>(); + readonly Func<TWrite, byte[]> serializer; readonly Func<byte[], TRead> 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/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs index f809f4a84c..513902ee36 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<TRequest, TResponse> : AsyncCallBase<TResponse, TRequest> { readonly TaskCompletionSource<object> finishedServersideTcs = new TaskCompletionSource<object>(); + readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); readonly GrpcEnvironment environment; public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer, GrpcEnvironment environment) : base(serializer, deserializer) @@ -118,6 +119,26 @@ namespace Grpc.Core.Internal } } + /// <summary> + /// Gets cancellation token that gets cancelled once close completion + /// is received and the cancelled flag is set. + /// </summary> + public CancellationToken CancellationToken + { + get + { + return cancellationTokenSource.Token; + } + } + + public string Peer + { + get + { + return call.GetPeer(); + } + } + protected override void OnReleaseResources() { environment.DebugStats.ActiveServerCalls.Decrement(); @@ -138,6 +159,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 +168,11 @@ namespace Grpc.Core.Internal } // TODO(jtattermusch): handle error + if (cancelled) + { + cancellationTokenSource.Cancel(); + } + finishedServersideTcs.SetResult(null); } } diff --git a/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs new file mode 100644 index 0000000000..92fbe8cf0f --- /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 +{ + /// <summary> + /// Owned char* object. + /// </summary> + 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 19dbb83f24..714749b171 100644 --- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs @@ -46,9 +46,6 @@ namespace Grpc.Core.Internal 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); [DllImport("grpc_csharp_ext.dll")] @@ -92,19 +89,15 @@ namespace Grpc.Core.Internal 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); private CallSafeHandle() { } - 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; @@ -190,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/ChannelSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs index f046f4c6d0..20815efbd3 100644 --- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs @@ -41,21 +41,24 @@ 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); [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); private ChannelSafeHandle() { } - 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) @@ -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/CompletionRegistry.cs b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs index f6d8aa0600..2796c959a3 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<CompletionRegistry>(); + readonly GrpcEnvironment environment; readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>(); @@ -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/CredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs index f361199068..8b4fa85e5d 100644 --- a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs @@ -50,9 +50,23 @@ namespace Grpc.Core.Internal { } - public static CredentialsSafeHandle CreateSslCredentials(string pemRootCerts) + public static CredentialsSafeHandle CreateNullCredentials() { - return grpcsharp_ssl_credentials_create(pemRootCerts, null, null); + var creds = new CredentialsSafeHandle(); + creds.SetHandle(IntPtr.Zero); + return creds; + } + + public static CredentialsSafeHandle CreateSslCredentials(string pemRootCerts, KeyCertificatePair keyCertPair) + { + 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/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs index b77e893044..cb4c7c821e 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 /// </summary> internal class GrpcThreadPool { + static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<GrpcThreadPool>(); + readonly GrpcEnvironment environment; readonly object myLock = new object(); readonly List<Thread> threads = new List<Thread>(); @@ -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 index 2f3c8ad71c..b8a55c5fe8 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 /// <summary> /// 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. /// </summary> - 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); /// <summary> - /// 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. /// </summary> - /// <param name="textWriter"></param> - 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 3680b1e791..19f0e3c57f 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<UnaryServerCallHandler<TRequest, TResponse>>(); + readonly Method<TRequest, TResponse> method; readonly UnaryServerMethod<TRequest, TResponse> handler; @@ -72,7 +75,7 @@ namespace Grpc.Core.Internal var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall); Status status; - var context = HandlerUtils.NewContext(newRpc); + var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken); try { Preconditions.CheckArgument(await requestStream.MoveNext()); @@ -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<ServerStreamingServerCallHandler<TRequest, TResponse>>(); + readonly Method<TRequest, TResponse> method; readonly ServerStreamingServerMethod<TRequest, TResponse> handler; @@ -126,7 +131,7 @@ namespace Grpc.Core.Internal var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall); Status status; - var context = HandlerUtils.NewContext(newRpc); + var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken); try { Preconditions.CheckArgument(await requestStream.MoveNext()); @@ -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<ClientStreamingServerCallHandler<TRequest, TResponse>>(); + readonly Method<TRequest, TResponse> method; readonly ClientStreamingServerMethod<TRequest, TResponse> handler; @@ -180,7 +187,7 @@ namespace Grpc.Core.Internal var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall); Status status; - var context = HandlerUtils.NewContext(newRpc); + var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken); try { var result = await handler(requestStream, context); @@ -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<DuplexStreamingServerCallHandler<TRequest, TResponse>>(); + readonly Method<TRequest, TResponse> method; readonly DuplexStreamingServerMethod<TRequest, TResponse> handler; @@ -238,7 +247,7 @@ namespace Grpc.Core.Internal var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall); Status status; - var context = HandlerUtils.NewContext(newRpc); + var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken); try { await handler(requestStream, responseStream, context); @@ -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 @@ -295,11 +304,13 @@ 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, string peer, CancellationToken cancellationToken) { + DateTime realtimeDeadline = newRpc.Deadline.ToClockType(GPRClockType.Realtime).ToDateTime(); + return new ServerCallContext( - newRpc.Method, newRpc.Host, newRpc.Deadline.ToDateTime(), - newRpc.RequestMetadata, CancellationToken.None); + newRpc.Method, newRpc.Host, peer, realtimeDeadline, + newRpc.RequestMetadata, cancellationToken); } } } diff --git a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs index 961180741a..59238a452c 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/Internal/ServerSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs index 9e1170e6dd..f9b44b1acf 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/Internal/Timespec.cs b/src/csharp/Grpc.Core/Internal/Timespec.cs index da2819f14d..e83d21f4a4 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 { /// <summary> @@ -40,32 +42,43 @@ 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_past(GPRClockType clockType); [DllImport("grpc_csharp_ext.dll")] - static extern Timespec gprsharp_inf_future(); + static extern Timespec gprsharp_convert_clock_type(Timespec t, GPRClockType targetClock); [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; /// <summary> /// Timespec a long time in the future. @@ -74,54 +87,164 @@ namespace Grpc.Core.Internal { get { - return gprsharp_inf_future(); + return gprsharp_inf_future(GPRClockType.Realtime); + } + } + + /// <summary> + /// Timespec a long time in the past. + /// </summary> + public static Timespec InfPast + { + get + { + return gprsharp_inf_past(GPRClockType.Realtime); } } + /// <summary> + /// Return Timespec representing the current time. + /// </summary> public static Timespec Now { get { - return gprsharp_now(); + return gprsharp_now(GPRClockType.Realtime); } } - - public DateTime ToDateTime() + + /// <summary> + /// Seconds since unix epoch. + /// </summary> + public IntPtr TimevalSeconds { - return UnixEpoch.AddTicks(tv_sec.ToInt64() * (NanosPerSecond / NanosPerTick) + tv_nsec / NanosPerTick); + get + { + return tv_sec; + } } - internal static int NativeSize + /// <summary> + /// The nanoseconds part of timeval. + /// </summary> + public int TimevalNanos { get { - return gprsharp_sizeof_timespec(); + return tv_nsec; } } /// <summary> - /// Creates a GPR deadline from current instant and given timeout. + /// Converts the timespec to desired clock type. /// </summary> - /// <returns>The from timeout.</returns> - public static Timespec DeadlineFromTimeout(TimeSpan timeout) + public Timespec ToClockType(GPRClockType targetClock) + { + return gprsharp_convert_clock_type(this, targetClock); + } + + /// <summary> + /// 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) + /// </summary> + public DateTime ToDateTime() { - if (timeout == Timeout.InfiniteTimeSpan) + 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; + } + + 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; + } + } + + /// <summary> + /// 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. + /// </summary> + /// <returns>The date time.</returns> + /// <param name="dateTime">Date time.</param> + public static Timespec FromDateTime(DateTime dateTime) + { + if (dateTime == DateTime.MaxValue) { return Timespec.InfFuture; } - return Timespec.Now.Add(timeout); + + if (dateTime == DateTime.MinValue) + { + return Timespec.InfPast; + } + + Preconditions.CheckArgument(dateTime.Kind == DateTimeKind.Utc, "dateTime"); + + try + { + TimeSpan timeSpan = dateTime - UnixEpoch; + long ticks = timeSpan.Ticks; + + 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) + { + return dateTime > UnixEpoch ? Timespec.InfFuture : Timespec.InfPast; + } + catch (ArgumentOutOfRangeException) + { + return dateTime > UnixEpoch ? Timespec.InfFuture : Timespec.InfPast; + } } - public Timespec Add(TimeSpan timeSpan) + 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/Grpc.Core/KeyCertificatePair.cs b/src/csharp/Grpc.Core/KeyCertificatePair.cs new file mode 100644 index 0000000000..7cea18618e --- /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 +{ + /// <summary> + /// Key certificate pair (in PEM encoding). + /// </summary> + public sealed class KeyCertificatePair + { + readonly string certificateChain; + readonly string privateKey; + + /// <summary> + /// Creates a new certificate chain - private key pair. + /// </summary> + /// <param name="certificateChain">PEM encoded certificate chain.</param> + /// <param name="privateKey">PEM encoded private key.</param> + public KeyCertificatePair(string certificateChain, string privateKey) + { + this.certificateChain = Preconditions.CheckNotNull(certificateChain); + this.privateKey = Preconditions.CheckNotNull(privateKey); + } + + /// <summary> + /// PEM encoded certificate chain. + /// </summary> + public string CertificateChain + { + get + { + return certificateChain; + } + } + + /// <summary> + /// PEM encoded private key. + /// </summary> + public string PrivateKey + { + get + { + return privateKey; + } + } + } +} diff --git a/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs new file mode 100644 index 0000000000..c67765c78d --- /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 +{ + /// <summary>Logger that logs to System.Console.</summary> + 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<T>() + { + 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 0000000000..0d58f133e3 --- /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 +{ + /// <summary>For logging messages.</summary> + public interface ILogger + { + /// <summary>Returns a logger associated with the specified type.</summary> + ILogger ForType<T>(); + + 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/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs index 2b3d7530f2..29db85d7aa 100644 --- a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs +++ b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs @@ -10,4 +10,12 @@ using System.Runtime.CompilerServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] +#if SIGNED +[assembly: InternalsVisibleTo("Grpc.Core.Tests,PublicKey=" + + "00240000048000009400000006020000002400005253413100040000010001002f5797a92c6fcde81bd4098f43" + + "0442bb8e12768722de0b0cb1b15e955b32a11352740ee59f2c94c48edc8e177d1052536b8ac651bce11ce5da3a" + + "27fc95aff3dc604a6971417453f9483c7b5e836756d5b271bf8f2403fe186e31956148c03d804487cf642f8cc0" + + "71394ee9672dfe5b55ea0f95dfd5a7f77d22c962ccf51320d3")] +#else [assembly: InternalsVisibleTo("Grpc.Core.Tests")] +#endif
\ No newline at end of file diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs index fd30735359..3217547cc4 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 /// </summary> public const int PickUnusedPort = 0; + static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<Server>(); + readonly GrpcEnvironment environment; readonly List<ChannelOption> options; readonly ServerSafeHandle handle; @@ -95,28 +98,31 @@ namespace Grpc.Core } /// <summary> - /// Add a non-secure port on which server should listen. + /// Add a port on which server should listen. /// Only call this before Start(). /// </summary> /// <returns>The port on which server will be listening.</returns> /// <param name="host">the host</param> /// <param name="port">the port. If zero, an unused port is chosen automatically.</param> - public int AddListeningPort(string host, int port) + public int AddPort(string host, int port, ServerCredentials credentials) { - return AddListeningPortInternal(host, port, null); - } - - /// <summary> - /// Add a non-secure port on which server should listen. - /// Only call this before Start(). - /// </summary> - /// <returns>The port on which server will be listening.</returns> - /// <param name="host">the host</param> - /// <param name="port">the port. If zero, an unused port is chosen automatically.</param> - 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); + } + } + } } /// <summary> @@ -183,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); - } - } - } - /// <summary> /// Allows one new RPC call to be received by server. /// </summary> @@ -233,7 +219,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/ServerCallContext.cs b/src/csharp/Grpc.Core/ServerCallContext.cs index 17a2eefd07..0c48adaea5 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 } } + /// <summary> Address of the remote endpoint in URI format. </summary> + public string Peer + { + get + { + return this.peer; + } + } + /// <summary> Deadline for this RPC. </summary> public DateTime Deadline { diff --git a/src/csharp/Grpc.Core/ServerCredentials.cs b/src/csharp/Grpc.Core/ServerCredentials.cs index ab7d0b4914..32ed4b78a1 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 { @@ -43,67 +44,99 @@ namespace Grpc.Core /// </summary> public abstract class ServerCredentials { + static readonly ServerCredentials InsecureInstance = new InsecureServerCredentialsImpl(); + + /// <summary> + /// Returns instance of credential that provides no security and + /// will result in creating an unsecure server port with no encryption whatsoever. + /// </summary> + public static ServerCredentials Insecure + { + get + { + return InsecureInstance; + } + } + /// <summary> /// Creates native object for the credentials. /// </summary> /// <returns>The native credentials.</returns> internal abstract ServerCredentialsSafeHandle ToNativeCredentials(); + + private sealed class InsecureServerCredentialsImpl : ServerCredentials + { + internal override ServerCredentialsSafeHandle ToNativeCredentials() + { + return null; + } + } } /// <summary> - /// Key certificate pair (in PEM encoding). + /// Server-side SSL credentials. /// </summary> - public class KeyCertificatePair + public class SslServerCredentials : ServerCredentials { - readonly string certChain; - readonly string privateKey; + readonly IList<KeyCertificatePair> keyCertificatePairs; + readonly string rootCertificates; - public KeyCertificatePair(string certChain, string privateKey) + /// <summary> + /// Creates server-side SSL credentials. + /// </summary> + /// <param name="rootCertificates">PEM encoded client root certificates used to authenticate client.</param> + /// <param name="keyCertificatePairs">Key-certificates to use.</param> + public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs, string rootCertificates) { - this.certChain = certChain; - this.privateKey = privateKey; + this.keyCertificatePairs = new List<KeyCertificatePair>(keyCertificatePairs).AsReadOnly(); + Preconditions.CheckArgument(this.keyCertificatePairs.Count > 0, + "At least one KeyCertificatePair needs to be provided"); + this.rootCertificates = rootCertificates; } - public string CertChain + /// <summary> + /// Creates server-side SSL credentials. + /// This constructor should be use if you do not wish to autheticate client + /// using client root certificates. + /// </summary> + /// <param name="keyCertificatePairs">Key-certificates to use.</param> + public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs) : this(keyCertificatePairs, null) { - get - { - return certChain; - } } - public string PrivateKey + /// <summary> + /// Key-certificate pairs. + /// </summary> + public IList<KeyCertificatePair> KeyCertificatePairs { get { - return privateKey; + return this.keyCertificatePairs; } } - } - - /// <summary> - /// Server-side SSL credentials. - /// </summary> - public class SslServerCredentials : ServerCredentials - { - ImmutableList<KeyCertificatePair> keyCertPairs; - public SslServerCredentials(ImmutableList<KeyCertificatePair> keyCertPairs) + /// <summary> + /// PEM encoded client root certificates. + /// </summary> + 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); } } } diff --git a/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs b/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs index 4180d98938..82653c3a1f 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 /// </summary> 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.Examples.MathClient/Grpc.Examples.MathClient.csproj b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj index 5d5401593d..b603e3af3c 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 @@ <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <ProductVersion>10.0.0</ProductVersion> <SchemaVersion>2.0</SchemaVersion> <ProjectGuid>{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}</ProjectGuid> @@ -11,7 +11,7 @@ <AssemblyName>MathClient</AssemblyName> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> @@ -19,17 +19,22 @@ <DefineConstants>DEBUG;</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <Externalconsole>true</Externalconsole> - <PlatformTarget>x86</PlatformTarget> </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> - <DebugType>full</DebugType> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release</OutputPath> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <Externalconsole>true</Externalconsole> - <PlatformTarget>x86</PlatformTarget> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\ReleaseSigned</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <SignAssembly>True</SignAssembly> + <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile> </PropertyGroup> <ItemGroup> <Reference Include="System" /> diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs index cfe2a06916..f9839d99f1 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/Grpc.Examples.MathServer.csproj b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj index 677d87da20..5f74b58773 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 @@ <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <ProductVersion>10.0.0</ProductVersion> <SchemaVersion>2.0</SchemaVersion> <ProjectGuid>{BF62FE08-373A-43D6-9D73-41CAA38B7011}</ProjectGuid> @@ -11,7 +11,7 @@ <AssemblyName>MathServer</AssemblyName> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> @@ -19,17 +19,22 @@ <DefineConstants>DEBUG;</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <Externalconsole>true</Externalconsole> - <PlatformTarget>x86</PlatformTarget> </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> - <DebugType>full</DebugType> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release</OutputPath> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <Externalconsole>true</Externalconsole> - <PlatformTarget>x86</PlatformTarget> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\ReleaseSigned</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <SignAssembly>True</SignAssembly> + <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile> </PropertyGroup> <ItemGroup> <Reference Include="System" /> diff --git a/src/csharp/Grpc.Examples.MathServer/MathServer.cs b/src/csharp/Grpc.Examples.MathServer/MathServer.cs index f440985112..468eefbe3e 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/Grpc.Examples.Tests.csproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj index d59d7515d1..9a8f780b24 100644 --- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj +++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj @@ -19,15 +19,22 @@ <DefineConstants>DEBUG;</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <ConsolePause>false</ConsolePause> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <DebugType>full</DebugType> + <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release</OutputPath> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <ConsolePause>false</ConsolePause> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\ReleaseSigned</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <SignAssembly>True</SignAssembly> + <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile> </PropertyGroup> <ItemGroup> <Reference Include="nunit.framework"> diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs index 7a957c5b6f..242d29a9a5 100644 --- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs +++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs @@ -56,16 +56,16 @@ 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 // for header support. client.HeaderInterceptor = (metadata) => { - metadata.Add(new Metadata.Entry("customHeader", "abcdef")); + metadata.Add(new Metadata.Entry("custom-header", "abcdef")); }; } @@ -108,69 +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); + } + + [Test] + public async Task Fib() + { + using (var call = client.Fib(new FibArgs.Builder { Limit = 6 }.Build())) { - DivReply response = await client.DivAsync(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build()); - Assert.AreEqual(3, response.Quotient); - Assert.AreEqual(1, response.Remainder); - }).Wait(); + var responses = await call.ResponseStream.ToList(); + CollectionAssert.AreEqual(new List<long> { 1, 1, 2, 3, 5, 8 }, + responses.ConvertAll((n) => n.Num_)); + } } [Test] - public void Fib() + 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)) { - using (var call = client.Fib(new FibArgs.Builder { Limit = 6 }.Build())) + List<long> responses = new List<long>(); + + 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) { - var responses = await call.ResponseStream.ToList(); - CollectionAssert.AreEqual(new List<long> { 1, 1, 2, 3, 5, 8 }, - responses.ConvertAll((n) => n.Num_)); + 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() + 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.Sum()) + try { - var numbers = new List<long> { 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_); + 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 DivMany() + public async Task Sum() { - Task.Run(async () => + using (var call = client.Sum()) { - var divArgsList = new List<DivArgs> - { - new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(), - new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(), - new DivArgs.Builder { Dividend = 7, Divisor = 2 }.Build() - }; + var numbers = new List<long> { 10, 20, 30 }.ConvertAll( + n => Num.CreateBuilder().SetNum_(n).Build()); - using (var call = client.DivMany()) - { - await call.RequestStream.WriteAll(divArgsList); - var result = await call.ResponseStream.ToList(); + await call.RequestStream.WriteAll(numbers); + var result = await call.ResponseAsync; + Assert.AreEqual(60, result.Num_); + } + } - 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(); + [Test] + public async Task DivMany() + { + var divArgsList = new List<DivArgs> + { + 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(); + + CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient)); + CollectionAssert.AreEqual(new long[] { 1, 16, 1 }, result.ConvertAll((divReply) => divReply.Remainder)); + } } } } diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.csproj b/src/csharp/Grpc.Examples/Grpc.Examples.csproj index eaf24a253c..c1aa40500e 100644 --- a/src/csharp/Grpc.Examples/Grpc.Examples.csproj +++ b/src/csharp/Grpc.Examples/Grpc.Examples.csproj @@ -19,15 +19,22 @@ <DefineConstants>DEBUG;</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <ConsolePause>false</ConsolePause> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <DebugType>full</DebugType> + <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release</OutputPath> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <ConsolePause>false</ConsolePause> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\ReleaseSigned</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <SignAssembly>True</SignAssembly> + <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile> </PropertyGroup> <ItemGroup> <Reference Include="System" /> diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs index ef787cf1d8..67827e7b4f 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<global::math.DivReply> DivAsync(global::math.DivArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncClientStreamingCall<global::math.Num, global::math.Num> 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<global::math.DivReply> DivAsync(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncClientStreamingCall<global::math.Num, global::math.Num> 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<global::math.DivReply> DivAsync(global::math.DivArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_Div, headers); + var call = CreateCall(__ServiceName, __Method_Div, headers, deadline); return Calls.AsyncUnaryCall(call, request, cancellationToken); } - public AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_DivMany, headers); + var call = CreateCall(__ServiceName, __Method_DivMany, headers, deadline); return Calls.AsyncDuplexStreamingCall(call, cancellationToken); } - public AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_Fib, headers); + var call = CreateCall(__ServiceName, __Method_Fib, headers, deadline); return Calls.AsyncServerStreamingCall(call, request, cancellationToken); } - public AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_Sum, headers); + var call = CreateCall(__ServiceName, __Method_Sum, headers, deadline); return Calls.AsyncClientStreamingCall(call, cancellationToken); } } diff --git a/src/csharp/Grpc.Examples/MathServiceImpl.cs b/src/csharp/Grpc.Examples/MathServiceImpl.cs index 3dd0f53a0d..dd26b1d350 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<Num> fibEnumerator = FibInternal(long.MaxValue).GetEnumerator(); + while (!context.CancellationToken.IsCancellationRequested && fibEnumerator.MoveNext()) + { + await responseStream.WriteAsync(fibEnumerator.Current); + await Task.Delay(100); + } } if (request.Limit > 0) diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj index 72e110302b..c922ddfb9e 100644 --- a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj +++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj @@ -17,7 +17,6 @@ <DebugType>full</DebugType> <Optimize>false</Optimize> <OutputPath>bin\Debug\</OutputPath> - <DefineConstants>DEBUG;TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> @@ -25,10 +24,18 @@ <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release\</OutputPath> - <DefineConstants>TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\ReleaseSigned</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <SignAssembly>True</SignAssembly> + <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile> + </PropertyGroup> <ItemGroup> <Reference Include="Google.ProtocolBuffers"> <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll</HintPath> diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs index bc14a0a62f..9d89698a8f 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.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj index 4ebb6446dd..0b7a7b91c6 100644 --- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj +++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj @@ -18,7 +18,6 @@ <DebugType>full</DebugType> <Optimize>false</Optimize> <OutputPath>bin\Debug\</OutputPath> - <DefineConstants>DEBUG;TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> @@ -26,10 +25,18 @@ <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release\</OutputPath> - <DefineConstants>TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\ReleaseSigned</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <SignAssembly>True</SignAssembly> + <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile> + </PropertyGroup> <ItemGroup> <Reference Include="Google.ProtocolBuffers"> <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll</HintPath> diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec index ca35b36805..acdfba42c8 100644 --- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec +++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec @@ -20,9 +20,9 @@ </dependencies> </metadata> <files> - <file src="bin/Release/Grpc.HealthCheck.dll" target="lib/net45" /> - <file src="bin/Release/Grpc.HealthCheck.pdb" target="lib/net45" /> - <file src="bin/Release/Grpc.HealthCheck.xml" target="lib/net45" /> + <file src="bin/ReleaseSigned/Grpc.HealthCheck.dll" target="lib/net45" /> + <file src="bin/ReleaseSigned/Grpc.HealthCheck.pdb" target="lib/net45" /> + <file src="bin/ReleaseSigned/Grpc.HealthCheck.xml" target="lib/net45" /> <file src="**\*.cs" target="src" /> </files> </package> diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs index 217127eca7..892cdb3f04 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<global::Grpc.Health.V1Alpha.HealthCheckResponse> 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<global::Grpc.Health.V1Alpha.HealthCheckResponse> 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<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_Check, headers); + var call = CreateCall(__ServiceName, __Method_Check, headers, deadline); return Calls.AsyncUnaryCall(call, request, cancellationToken); } } diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj index dc1d0a44c0..2c38c9645c 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 @@ <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <ProjectGuid>{3D166931-BA2D-416E-95A3-D36E8F6E90B9}</ProjectGuid> <OutputType>Exe</OutputType> <RootNamespace>Grpc.IntegrationTesting.Client</RootNamespace> @@ -10,7 +10,7 @@ <StartupObject>Grpc.IntegrationTesting.Client.Program</StartupObject> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> @@ -18,17 +18,24 @@ <DefineConstants>DEBUG;</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <Externalconsole>true</Externalconsole> - <PlatformTarget>x86</PlatformTarget> + <PlatformTarget>AnyCPU</PlatformTarget> </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> - <DebugType>full</DebugType> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release</OutputPath> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <Externalconsole>true</Externalconsole> - <PlatformTarget>x86</PlatformTarget> + <PlatformTarget>AnyCPU</PlatformTarget> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\ReleaseSigned</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <SignAssembly>True</SignAssembly> + <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile> </PropertyGroup> <ItemGroup> <Reference Include="System" /> diff --git a/src/csharp/Grpc.IntegrationTesting.Client/app.config b/src/csharp/Grpc.IntegrationTesting.Client/app.config index 966b777192..0a82bb4f16 100644 --- a/src/csharp/Grpc.IntegrationTesting.Client/app.config +++ b/src/csharp/Grpc.IntegrationTesting.Client/app.config @@ -4,7 +4,7 @@ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" /> + <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj index f03c8f3ce3..949ad61375 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 @@ <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <ProjectGuid>{A654F3B8-E859-4E6A-B30D-227527DBEF0D}</ProjectGuid> <OutputType>Exe</OutputType> <RootNamespace>Grpc.IntegrationTesting.Server</RootNamespace> @@ -10,7 +10,7 @@ <StartupObject>Grpc.IntegrationTesting.Server.Program</StartupObject> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> @@ -18,17 +18,24 @@ <DefineConstants>DEBUG;</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <Externalconsole>true</Externalconsole> - <PlatformTarget>x86</PlatformTarget> + <PlatformTarget>AnyCPU</PlatformTarget> </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> - <DebugType>full</DebugType> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release</OutputPath> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <Externalconsole>true</Externalconsole> - <PlatformTarget>x86</PlatformTarget> + <PlatformTarget>AnyCPU</PlatformTarget> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\ReleaseSigned</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <SignAssembly>True</SignAssembly> + <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile> </PropertyGroup> <ItemGroup> <Reference Include="System" /> diff --git a/src/csharp/Grpc.IntegrationTesting.Server/app.config b/src/csharp/Grpc.IntegrationTesting.Server/app.config index 966b777192..0a82bb4f16 100644 --- a/src/csharp/Grpc.IntegrationTesting.Server/app.config +++ b/src/csharp/Grpc.IntegrationTesting.Server/app.config @@ -4,7 +4,7 @@ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" /> + <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj index d3c69ab9eb..abc27f811e 100644 --- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj +++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj @@ -2,16 +2,15 @@ <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">x86</Platform> - <ProductVersion>8.0.30703</ProductVersion> - <SchemaVersion>2.0</SchemaVersion> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <ProjectGuid>{C61154BA-DD4A-4838-8420-0162A28925E0}</ProjectGuid> <OutputType>Library</OutputType> <RootNamespace>Grpc.IntegrationTesting</RootNamespace> <AssemblyName>Grpc.IntegrationTesting</AssemblyName> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <NuGetPackageImportStamp>041c163e</NuGetPackageImportStamp> </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> @@ -19,46 +18,44 @@ <DefineConstants>DEBUG;</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <Externalconsole>true</Externalconsole> - <PlatformTarget>x86</PlatformTarget> + <PlatformTarget>AnyCPU</PlatformTarget> </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> - <DebugType>full</DebugType> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release</OutputPath> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> - <Externalconsole>true</Externalconsole> - <PlatformTarget>x86</PlatformTarget> + <PlatformTarget>AnyCPU</PlatformTarget> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\ReleaseSigned</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <SignAssembly>True</SignAssembly> + <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile> </PropertyGroup> <ItemGroup> - <Reference Include="Google.Apis.Auth, Version=1.9.1.12395, Culture=neutral, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.dll</HintPath> + <Reference Include="BouncyCastle.Crypto"> + <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath> </Reference> - <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.1.12399, Culture=neutral, processorArchitecture=MSIL"> + <Reference Include="Google.Apis.Auth, Version=1.9.2.27817, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath> + <HintPath>..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.dll</HintPath> </Reference> - <Reference Include="Google.Apis.Core, Version=1.9.1.12394, Culture=neutral, processorArchitecture=MSIL"> + <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.2.27820, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\Google.Apis.Core.1.9.1\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath> - </Reference> - <Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath> - </Reference> - <Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath> + <HintPath>..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath> </Reference> - <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <Reference Include="Google.Apis.Core, Version=1.9.2.27816, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath> + <HintPath>..\packages\Google.Apis.Core.1.9.2\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath> </Reference> - <Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> + <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll</HintPath> + <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> </Reference> <Reference Include="nunit.framework"> <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath> @@ -67,24 +64,32 @@ <Reference Include="Google.ProtocolBuffers"> <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll</HintPath> </Reference> - <Reference Include="System.Collections.Immutable, Version=1.1.36.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath> - </Reference> <Reference Include="System.Interactive.Async"> <HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath> </Reference> <Reference Include="System.Net" /> <Reference Include="System.Net.Http" /> - <Reference Include="System.Net.Http.Extensions, Version=2.2.28.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll</HintPath> + <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath> </Reference> - <Reference Include="System.Net.Http.Primitives, Version=4.2.28.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll</HintPath> + <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath> </Reference> <Reference Include="System.Net.Http.WebRequest" /> + <Reference Include="Microsoft.Threading.Tasks"> + <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath> + </Reference> + <Reference Include="Microsoft.Threading.Tasks.Extensions"> + <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath> + </Reference> + <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop"> + <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath> + </Reference> + <Reference Include="System.Collections.Immutable"> + <HintPath>..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath> + </Reference> </ItemGroup> <ItemGroup> <Compile Include="..\Grpc.Core\Version.cs"> @@ -99,6 +104,7 @@ <Compile Include="InteropClient.cs" /> <Compile Include="TestCredentials.cs" /> <Compile Include="TestGrpc.cs" /> + <Compile Include="SslCredentialsTest.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <ItemGroup> @@ -133,9 +139,11 @@ <ItemGroup> <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> </ItemGroup> - <Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" /> - <Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''"> - <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" /> - <Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" /> + <Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" /> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" /> </Target> </Project>
\ No newline at end of file diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index ce255f9423..7411d91d5a 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -127,15 +127,15 @@ namespace Grpc.IntegrationTesting { credential = credential.CreateScoped(new[] { AuthScope }); } - client.HeaderInterceptor = OAuth2InterceptorFactory.Create(credential); + client.HeaderInterceptor = OAuth2Interceptors.FromCredential(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<int> { 27182, 8, 1828, 45904 }.ConvertAll((size) => StreamingInputCallRequest.CreateBuilder().SetPayload(CreateZerosPayload(size)).Build()); + var bodySizes = new List<int> { 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<int> { 31415, 9, 2653, 58979 }; + var bodySizes = new List<int> { 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) @@ -368,11 +356,7 @@ namespace Grpc.IntegrationTesting Assert.IsTrue(credential.RequestAccessTokenAsync(CancellationToken.None).Result); string oauth2Token = credential.Token.AccessToken; - // Intercept calls with an OAuth2 token obtained out-of-band. - client.HeaderInterceptor = new MetadataInterceptorDelegate((metadata) => - { - metadata.Add(new Metadata.Entry("Authorization", "Bearer " + oauth2Token)); - }); + client.HeaderInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token); var request = SimpleRequest.CreateBuilder() .SetFillUsername(true) @@ -393,78 +377,75 @@ namespace Grpc.IntegrationTesting var credential = GoogleCredential.GetApplicationDefault().CreateScoped(new[] { AuthScope }); Assert.IsTrue(credential.RequestAccessTokenAsync(CancellationToken.None).Result); string oauth2Token = credential.Token.AccessToken; + var headerInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token); var request = SimpleRequest.CreateBuilder() .SetFillUsername(true) .SetFillOauthScope(true) .Build(); - var response = client.UnaryCall(request, headers: new Metadata { new Metadata.Entry("Authorization", "Bearer " + oauth2Token) }); + var headers = new Metadata(); + headerInterceptor(headers); + var response = client.UnaryCall(request, headers: headers); Assert.AreEqual(AuthScopeResponse, response.OauthScope); Assert.AreEqual(ServiceAccountUser, response.Username); 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(); } - Console.WriteLine("Passed!"); - }).Wait(); + catch (RpcException e) + { + Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode); + } + } + 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 f306289cfb..2756ce97aa 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<ChannelOption> @@ -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); } } } diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs index 9475e66c40..bf6947e09d 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 new file mode 100644 index 0000000000..1baf40eea2 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs @@ -0,0 +1,97 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using grpc.testing; +using Grpc.Core; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.IntegrationTesting +{ + /// <summary> + /// Test SSL credentials where server authenticates client + /// and client authenticates the server. + /// </summary> + 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.AddPort(host, Server.PickUnusedPort, serverCredentials); + server.Start(); + + var options = new List<ChannelOption> + { + 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 401c50b1ae..54d8587713 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 }); } } } diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs index de2fa07441..ddcd0c2958 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<global::grpc.testing.Empty> 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<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> 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<global::grpc.testing.Empty> 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<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> 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<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_EmptyCall, headers); + 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<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_UnaryCall, headers); + var call = CreateCall(__ServiceName, __Method_UnaryCall, headers, deadline); return Calls.AsyncUnaryCall(call, request, cancellationToken); } - public AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_StreamingOutputCall, headers); + var call = CreateCall(__ServiceName, __Method_StreamingOutputCall, headers, deadline); return Calls.AsyncServerStreamingCall(call, request, cancellationToken); } - public AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_StreamingInputCall, headers); + var call = CreateCall(__ServiceName, __Method_StreamingInputCall, headers, deadline); return Calls.AsyncClientStreamingCall(call, cancellationToken); } - public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_FullDuplexCall, headers); + var call = CreateCall(__ServiceName, __Method_FullDuplexCall, headers, deadline); return Calls.AsyncDuplexStreamingCall(call, cancellationToken); } - public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_HalfDuplexCall, headers); + var call = CreateCall(__ServiceName, __Method_HalfDuplexCall, headers, deadline); return Calls.AsyncDuplexStreamingCall(call, cancellationToken); } } diff --git a/src/csharp/Grpc.IntegrationTesting/app.config b/src/csharp/Grpc.IntegrationTesting/app.config index 966b777192..0a82bb4f16 100644 --- a/src/csharp/Grpc.IntegrationTesting/app.config +++ b/src/csharp/Grpc.IntegrationTesting/app.config @@ -4,7 +4,7 @@ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" /> + <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config index c74ac75d79..746133a7a5 100644 --- a/src/csharp/Grpc.IntegrationTesting/packages.config +++ b/src/csharp/Grpc.IntegrationTesting/packages.config @@ -1,14 +1,15 @@ <?xml version="1.0" encoding="utf-8"?> <packages> - <package id="Google.Apis.Auth" version="1.9.1" targetFramework="net45" /> - <package id="Google.Apis.Core" version="1.9.1" targetFramework="net45" /> + <package id="BouncyCastle" version="1.7.0" targetFramework="net45" /> + <package id="Google.Apis.Auth" version="1.9.2" targetFramework="net45" /> + <package id="Google.Apis.Core" version="1.9.2" targetFramework="net45" /> <package id="Google.ProtocolBuffers" version="2.4.1.521" targetFramework="net45" /> <package id="Ix-Async" version="1.2.3" targetFramework="net45" /> - <package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" /> + <package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" /> <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" /> - <package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" /> - <package id="Microsoft.Net.Http" version="2.2.28" targetFramework="net45" /> - <package id="Newtonsoft.Json" version="6.0.6" targetFramework="net45" /> + <package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" /> + <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" /> + <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" /> <package id="NUnit" version="2.6.4" targetFramework="net45" /> <package id="System.Collections.Immutable" version="1.1.36" targetFramework="net45" /> </packages>
\ No newline at end of file diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln index 705e4fb1c2..f19f29c6a2 100644 --- a/src/csharp/Grpc.sln +++ b/src/csharp/Grpc.sln @@ -34,60 +34,83 @@ 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
+ ReleaseSigned|Any CPU = ReleaseSigned|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
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
+ {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
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|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
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|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
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|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
+ {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|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
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|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
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|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
+ {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|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
+ {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|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
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|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
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|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
+ {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|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
+ {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat index c3e5fe8817..9e1253bf0b 100644 --- a/src/csharp/build_packages.bat +++ b/src/csharp/build_packages.bat @@ -12,7 +12,7 @@ cd ..\..\vsprojects\nuget_package @call buildall.bat || goto :error endlocal -@call buildall.bat || goto :error +@call buildall.bat BUILD_SIGNED || goto :error %NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp_ext.nuspec -Version %CORE_VERSION% || goto :error %NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error diff --git a/src/csharp/buildall.bat b/src/csharp/buildall.bat index 16860aec3c..e73feb87b9 100644 --- a/src/csharp/buildall.bat +++ b/src/csharp/buildall.bat @@ -13,6 +13,11 @@ msbuild ..\..\vsprojects\grpc.sln /t:grpc_csharp_ext /p:PlatformToolset=v120 || msbuild Grpc.sln /p:Configuration=Debug || goto :error msbuild Grpc.sln /p:Configuration=Release || goto :error + +if "%1" == "BUILD_SIGNED" ( +msbuild Grpc.sln /p:Configuration=ReleaseSigned || goto :error +) + endlocal goto :EOF diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index ae8186398a..49a0471042 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -366,8 +366,9 @@ 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) { - return grpc_channel_create(target, args); + +grpcsharp_insecure_channel_create(const char *target, const grpc_channel_args *args) { + return grpc_insecure_channel_create(target, args); } GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_destroy(grpc_channel *channel) { @@ -432,10 +433,20 @@ 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_past(gpr_clock_type clock_type) { + return gpr_inf_past(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_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) { @@ -454,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); } @@ -695,7 +714,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); } @@ -772,8 +791,9 @@ grpcsharp_ssl_server_credentials_create( key_cert_pairs[i].private_key = key_cert_pair_private_key_array[i]; } } + /* TODO: Add a force_client_auth parameter and pass it here. */ creds = grpc_ssl_server_credentials_create(pem_root_certs, key_cert_pairs, - num_key_cert_pairs); + num_key_cert_pairs, 0); gpr_free(key_cert_pairs); return creds; } diff --git a/src/csharp/keys/Grpc.public.snk b/src/csharp/keys/Grpc.public.snk Binary files differnew file mode 100644 index 0000000000..bac3046b36 --- /dev/null +++ b/src/csharp/keys/Grpc.public.snk diff --git a/src/csharp/keys/README.md b/src/csharp/keys/README.md new file mode 100644 index 0000000000..f3e9a3cb56 --- /dev/null +++ b/src/csharp/keys/README.md @@ -0,0 +1,5 @@ +Contents +-------- + +- Grpc.public.snk: + Public key to verify strong name of gRPC assemblies.
\ No newline at end of file diff --git a/src/node/README.md b/src/node/README.md index 78781dab14..7d3d8c7fa1 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 diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc index 15c9b2d97d..dc45c8d8ae 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"; } }; @@ -453,6 +453,8 @@ void Call::Init(Handle<Object> exports) { NanNew<FunctionTemplate>(StartBatch)->GetFunction()); NanSetPrototypeTemplate(tpl, "cancel", NanNew<FunctionTemplate>(Cancel)->GetFunction()); + NanSetPrototypeTemplate(tpl, "getPeer", + NanNew<FunctionTemplate>(GetPeer)->GetFunction()); NanAssignPersistent(fun_tpl, tpl); Handle<Function> 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<Call>(args.This()); + char *peer = grpc_call_get_peer(call->wrapped_call); + Handle<Value> 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 43142c7091..6acda76197 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<v8::FunctionTemplate> fun_tpl; diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc index d37bf763dd..c43b55f115 100644 --- a/src/node/ext/channel.cc +++ b/src/node/ext/channel.cc @@ -76,6 +76,8 @@ void Channel::Init(Handle<Object> exports) { tpl->InstanceTemplate()->SetInternalFieldCount(1); NanSetPrototypeTemplate(tpl, "close", NanNew<FunctionTemplate>(Close)->GetFunction()); + NanSetPrototypeTemplate(tpl, "getTarget", + NanNew<FunctionTemplate>(GetTarget)->GetFunction()); NanAssignPersistent(fun_tpl, tpl); Handle<Function> ctr = tpl->GetFunction(); constructor = new NanCallback(ctr); @@ -103,7 +105,7 @@ NAN_METHOD(Channel::New) { NanUtf8String *host = new NanUtf8String(args[0]); NanUtf8String *host_override = NULL; if (args[1]->IsUndefined()) { - wrapped_channel = grpc_channel_create(**host, NULL); + wrapped_channel = grpc_insecure_channel_create(**host, NULL); } else if (args[1]->IsObject()) { grpc_credentials *creds = NULL; Handle<Object> args_hash(args[1]->ToObject()->Clone()); @@ -148,7 +150,7 @@ NAN_METHOD(Channel::New) { } } if (creds == NULL) { - wrapped_channel = grpc_channel_create(**host, &channel_args); + wrapped_channel = grpc_insecure_channel_create(**host, &channel_args); } else { wrapped_channel = grpc_secure_channel_create(creds, **host, &channel_args); @@ -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<Channel>(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 b3aa0f700f..6725ebb03f 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<v8::FunctionTemplate> fun_tpl; diff --git a/src/node/ext/credentials.cc b/src/node/ext/credentials.cc index 34872017ea..d6cff0631d 100644 --- a/src/node/ext/credentials.cc +++ b/src/node/ext/credentials.cc @@ -79,8 +79,6 @@ void Credentials::Init(Handle<Object> exports) { NanNew<FunctionTemplate>(CreateComposite)->GetFunction()); ctr->Set(NanNew("createGce"), NanNew<FunctionTemplate>(CreateGce)->GetFunction()); - ctr->Set(NanNew("createFake"), - NanNew<FunctionTemplate>(CreateFake)->GetFunction()); ctr->Set(NanNew("createIam"), NanNew<FunctionTemplate>(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/node/ext/server.cc b/src/node/ext/server.cc index 34cde9ffab..8554fce777 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/ext/server_credentials.cc b/src/node/ext/server_credentials.cc index d2b63cdc4e..c4a93a6465 100644 --- a/src/node/ext/server_credentials.cc +++ b/src/node/ext/server_credentials.cc @@ -73,8 +73,6 @@ void ServerCredentials::Init(Handle<Object> exports) { Handle<Function> ctr = tpl->GetFunction(); ctr->Set(NanNew("createSsl"), NanNew<FunctionTemplate>(CreateSsl)->GetFunction()); - ctr->Set(NanNew("createFake"), - NanNew<FunctionTemplate>(CreateFake)->GetFunction()); constructor = new NanCallback(ctr); exports->Set(NanNew("ServerCredentials"), ctr); } @@ -140,14 +138,10 @@ NAN_METHOD(ServerCredentials::CreateSsl) { return NanThrowTypeError("createSsl's third argument must be a Buffer"); } key_cert_pair.cert_chain = ::node::Buffer::Data(args[2]); + // TODO Add a force_client_auth parameter and pass it as the last parameter + // here. NanReturnValue(WrapStruct( - 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())); + grpc_ssl_server_credentials_create(root_certs, &key_cert_pair, 1, 0))); } } // namespace node diff --git a/src/node/ext/server_credentials.h b/src/node/ext/server_credentials.h index aaa7ef297a..80747504a1 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<v8::FunctionTemplate> fun_tpl; diff --git a/src/node/ext/timeval.cc b/src/node/ext/timeval.cc index 60de4d816d..bf68513c48 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<double>::infinity(); } else if (gpr_time_cmp(timespec, gpr_inf_past(GPR_CLOCK_REALTIME)) == 0) { diff --git a/src/node/index.js b/src/node/index.js index d81e780443..b26ab35f2c 100644 --- a/src/node/index.js +++ b/src/node/index.js @@ -48,7 +48,7 @@ var grpc = require('bindings')('grpc'); * @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load. * @return {Object<string, *>} The resulting gRPC object */ -function loadObject(value) { +exports.loadObject = function loadObject(value) { var result = {}; if (value.className === 'Namespace') { _.each(value.children, function(child) { @@ -62,7 +62,9 @@ function loadObject(value) { } else { return value; } -} +}; + +var loadObject = exports.loadObject; /** * Load a gRPC object from a .proto file. @@ -71,7 +73,7 @@ function loadObject(value) { * 'json'. Defaults to 'proto' * @return {Object<string, *>} The resulting gRPC object */ -function load(filename, format) { +exports.load = function load(filename, format) { if (!format) { format = 'proto'; } @@ -88,7 +90,7 @@ function load(filename, format) { } return loadObject(builder.ns); -} +}; /** * Get a function that a client can use to update metadata with authentication @@ -97,7 +99,7 @@ function load(filename, format) { * @param {Object} credential The credential object to use * @return {function(Object, callback)} Metadata updater function */ -function getGoogleAuthDelegate(credential) { +exports.getGoogleAuthDelegate = function getGoogleAuthDelegate(credential) { /** * Update a metadata object with authentication information. * @param {string} authURI The uri to authenticate to @@ -120,20 +122,10 @@ function getGoogleAuthDelegate(credential) { callback(null, metadata); }); }; -} - -/** - * See docs for loadObject - */ -exports.loadObject = loadObject; +}; /** - * See docs for load - */ -exports.load = load; - -/** - * See docs for Server + * @see module:src/server.Server */ exports.Server = server.Server; @@ -141,6 +133,7 @@ exports.Server = server.Server; * Status name to code number mapping */ exports.status = grpc.status; + /** * Call error name to code number mapping */ @@ -156,6 +149,7 @@ exports.Credentials = grpc.Credentials; */ exports.ServerCredentials = grpc.ServerCredentials; -exports.getGoogleAuthDelegate = getGoogleAuthDelegate; - +/** + * @see module:src/client.makeClientConstructor + */ exports.makeGenericClientConstructor = client.makeClientConstructor; diff --git a/src/node/jsdoc_conf.json b/src/node/jsdoc_conf.json new file mode 100644 index 0000000000..876a8e19c6 --- /dev/null +++ b/src/node/jsdoc_conf.json @@ -0,0 +1,22 @@ +{ + "tags": { + "allowUnknownTags": true + }, + "source": { + "include": [ "index.js", "src" ], + "includePattern": ".+\\.js(doc)?$", + "excludePattern": "(^|\\/|\\\\)_" + }, + "opts": { + "package": "package.json", + "readme": "README.md" + }, + "plugins": [], + "templates": { + "cleverLinks": false, + "monospaceLinks": false, + "default": { + "outputSourceFiles": true + } + } +} diff --git a/src/node/package.json b/src/node/package.json index 1caf158792..756d41b0af 100644 --- a/src/node/package.json +++ b/src/node/package.json @@ -21,7 +21,8 @@ }, "scripts": { "lint": "node ./node_modules/jshint/bin/jshint src test examples interop index.js", - "test": "node ./node_modules/mocha/bin/mocha && npm run-script lint" + "test": "node ./node_modules/mocha/bin/mocha && npm run-script lint", + "gen_docs": "./node_modules/.bin/jsdoc -c jsdoc_conf.json" }, "dependencies": { "bindings": "^1.2.0", @@ -32,6 +33,7 @@ "devDependencies": { "async": "^0.9.0", "google-auth-library": "^0.9.2", + "jsdoc": "^3.3.2", "jshint": "^2.5.0", "minimist": "^1.1.0", "mocha": "~1.21.0", diff --git a/src/node/src/client.js b/src/node/src/client.js index da6327b432..f843669bd0 100644 --- a/src/node/src/client.js +++ b/src/node/src/client.js @@ -31,6 +31,11 @@ * */ +/** + * Server module + * @module + */ + 'use strict'; var _ = require('lodash'); @@ -72,6 +77,7 @@ function ClientWritableStream(call, serialize) { /** * Attempt to write the given chunk. Calls the callback when done. This is an * implementation of a method needed for implementing stream.Writable. + * @access private * @param {Buffer} chunk The chunk to write * @param {string} encoding Ignored * @param {function(Error=)} callback Called when the write is complete @@ -110,6 +116,7 @@ function ClientReadableStream(call, deserialize) { /** * Read the next object from the stream. + * @access private * @param {*} size Ignored because we use objectMode=true */ function _read(size) { @@ -188,6 +195,19 @@ 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 * @param {function(*):Buffer} serialize The serialization function for inputs @@ -223,6 +243,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(); @@ -503,7 +526,7 @@ var requester_makers = { * @param {string} serviceName The name of the service * @return {function(string, Object)} New client constructor */ -function makeClientConstructor(methods, serviceName) { +exports.makeClientConstructor = function(methods, serviceName) { /** * Create a client with the given methods * @constructor @@ -552,7 +575,7 @@ function makeClientConstructor(methods, serviceName) { }); return Client; -} +}; /** * Creates a constructor for clients for the given service @@ -560,22 +583,18 @@ function makeClientConstructor(methods, serviceName) { * for * @return {function(string, Object)} New client constructor */ -function makeProtobufClientConstructor(service) { +exports.makeProtobufClientConstructor = function(service) { var method_attrs = common.getProtobufServiceAttrs(service, service.name); - var Client = makeClientConstructor(method_attrs); + var Client = exports.makeClientConstructor(method_attrs); Client.service = service; - return Client; -} - -exports.makeClientConstructor = makeClientConstructor; - -exports.makeProtobufClientConstructor = makeProtobufClientConstructor; +}; /** - * See docs for client.status + * Map of status code names to status codes */ exports.status = grpc.status; + /** * See docs for client.callError */ diff --git a/src/node/src/common.js b/src/node/src/common.js index feaa859a4f..5551ebeec8 100644 --- a/src/node/src/common.js +++ b/src/node/src/common.js @@ -31,6 +31,10 @@ * */ +/** + * @module + */ + 'use strict'; var _ = require('lodash'); @@ -40,7 +44,7 @@ var _ = require('lodash'); * @param {function()} cls The constructor of the message type to deserialize * @return {function(Buffer):cls} The deserialization function */ -function deserializeCls(cls) { +exports.deserializeCls = function deserializeCls(cls) { /** * Deserialize a buffer to a message object * @param {Buffer} arg_buf The buffer to deserialize @@ -51,14 +55,16 @@ function deserializeCls(cls) { // and longs as strings (second argument) return cls.decode(arg_buf).toRaw(false, true); }; -} +}; + +var deserializeCls = exports.deserializeCls; /** * Get a function that serializes objects to a buffer by protobuf class. * @param {function()} Cls The constructor of the message type to serialize * @return {function(Cls):Buffer} The serialization function */ -function serializeCls(Cls) { +exports.serializeCls = function serializeCls(Cls) { /** * Serialize an object to a Buffer * @param {Object} arg The object to serialize @@ -67,14 +73,16 @@ function serializeCls(Cls) { return function serialize(arg) { return new Buffer(new Cls(arg).encode().toBuffer()); }; -} +}; + +var serializeCls = exports.serializeCls; /** * Get the fully qualified (dotted) name of a ProtoBuf.Reflect value. * @param {ProtoBuf.Reflect.Namespace} value The value to get the name of * @return {string} The fully qualified name of the value */ -function fullyQualifiedName(value) { +exports.fullyQualifiedName = function fullyQualifiedName(value) { if (value === null || value === undefined) { return ''; } @@ -89,7 +97,9 @@ function fullyQualifiedName(value) { } } return name; -} +}; + +var fullyQualifiedName = exports.fullyQualifiedName; /** * Wrap a function to pass null-like values through without calling it. If no @@ -97,7 +107,7 @@ function fullyQualifiedName(value) { * @param {?function} func The function to wrap * @return {function} The wrapped function */ -function wrapIgnoreNull(func) { +exports.wrapIgnoreNull = function wrapIgnoreNull(func) { if (!func) { return _.identity; } @@ -107,14 +117,14 @@ function wrapIgnoreNull(func) { } return func(arg); }; -} +}; /** * Return a map from method names to method attributes for the service. * @param {ProtoBuf.Reflect.Service} service The service to get attributes for * @return {Object} The attributes map */ -function getProtobufServiceAttrs(service) { +exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service) { var prefix = '/' + fullyQualifiedName(service) + '/'; return _.object(_.map(service.children, function(method) { return [_.camelCase(method.name), { @@ -127,26 +137,4 @@ function getProtobufServiceAttrs(service) { responseDeserialize: deserializeCls(method.resolvedResponseType.build()) }]; })); -} - -/** - * See docs for deserializeCls - */ -exports.deserializeCls = deserializeCls; - -/** - * See docs for serializeCls - */ -exports.serializeCls = serializeCls; - -/** - * See docs for fullyQualifiedName - */ -exports.fullyQualifiedName = fullyQualifiedName; - -/** - * See docs for wrapIgnoreNull - */ -exports.wrapIgnoreNull = wrapIgnoreNull; - -exports.getProtobufServiceAttrs = getProtobufServiceAttrs; +}; diff --git a/src/node/src/server.js b/src/node/src/server.js index 0a3a0031bd..9fbd1ee3bd 100644 --- a/src/node/src/server.js +++ b/src/node/src/server.js @@ -31,6 +31,11 @@ * */ +/** + * Server module + * @module + */ + 'use strict'; var _ = require('lodash'); @@ -50,6 +55,7 @@ var EventEmitter = require('events').EventEmitter; /** * Handle an error on a call by sending it as a status + * @access private * @param {grpc.Call} call The call to send the error on * @param {Object} error The error object */ @@ -82,6 +88,7 @@ function handleError(call, error) { /** * Wait for the client to close, then emit a cancelled event if the client * cancelled. + * @access private * @param {grpc.Call} call The call object to wait on * @param {EventEmitter} emitter The event emitter to emit the cancelled event * on @@ -102,6 +109,7 @@ function waitForCancel(call, emitter) { /** * Send a response to a unary or client streaming call. + * @access private * @param {grpc.Call} call The call to respond on * @param {*} value The value to respond with * @param {function(*):Buffer=} serialize Serialization function for the @@ -130,6 +138,7 @@ function sendUnaryResponse(call, value, serialize, metadata) { /** * Initialize a writable stream. This is used for both the writable and duplex * stream constructors. + * @access private * @param {Writable} stream The stream to set up * @param {function(*):Buffer=} Serialization function for responses */ @@ -203,6 +212,7 @@ function setUpWritable(stream, serialize) { /** * Initialize a readable stream. This is used for both the readable and duplex * stream constructors. + * @access private * @param {Readable} stream The stream to initialize * @param {function(Buffer):*=} deserialize Deserialization function for * incoming data. @@ -242,6 +252,7 @@ function ServerWritableStream(call, serialize) { /** * Start writing a chunk of data. This is an implementation of a method required * for implementing stream.Writable. + * @access private * @param {Buffer} chunk The chunk of data to write * @param {string} encoding Ignored * @param {function(Error=)} callback Callback to indicate that the write is @@ -266,6 +277,11 @@ function _write(chunk, encoding, callback) { ServerWritableStream.prototype._write = _write; +/** + * Send the initial metadata for a writable stream. + * @param {Object<String, Array<(String|Buffer)>>} responseMetadata Metadata + * to send + */ function sendMetadata(responseMetadata) { /* jshint validthis: true */ if (!this.call.metadataSent) { @@ -281,6 +297,10 @@ function sendMetadata(responseMetadata) { } } +/** + * @inheritdoc + * @alias module:src/server~ServerWritableStream#sendMetadata + */ ServerWritableStream.prototype.sendMetadata = sendMetadata; util.inherits(ServerReadableStream, Readable); @@ -301,6 +321,7 @@ function ServerReadableStream(call, deserialize) { /** * Start reading from the gRPC data source. This is an implementation of a * method required for implementing stream.Readable + * @access private * @param {number} size Ignored */ function _read(size) { @@ -374,7 +395,21 @@ 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 + * @access private * @param {grpc.Call} call The call to handle * @param {Object} handler Request handler object for the method that was called * @param {Object} metadata Metadata from the client @@ -389,6 +424,9 @@ function handleUnary(call, handler, metadata) { call.startBatch(batch, function() {}); } }; + emitter.getPeer = function() { + return call.getPeer(); + }; emitter.on('error', function(error) { handleError(call, error); }); @@ -426,6 +464,7 @@ function handleUnary(call, handler, metadata) { /** * Fully handle a server streaming call + * @access private * @param {grpc.Call} call The call to handle * @param {Object} handler Request handler object for the method that was called * @param {Object} metadata Metadata from the client @@ -454,6 +493,7 @@ function handleServerStreaming(call, handler, metadata) { /** * Fully handle a client streaming call + * @access private * @param {grpc.Call} call The call to handle * @param {Object} handler Request handler object for the method that was called * @param {Object} metadata Metadata from the client @@ -488,6 +528,7 @@ function handleClientStreaming(call, handler, metadata) { /** * Fully handle a bidirectional streaming call + * @access private * @param {grpc.Call} call The call to handle * @param {Object} handler Request handler object for the method that was called * @param {Object} metadata Metadata from the client @@ -544,7 +585,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; @@ -571,7 +612,8 @@ function Server(options) { } server.requestCall(handleNewCall); }; - /** Shuts down the server. + /** + * Shuts down the server. */ this.shutdown = function() { server.shutdown(); @@ -605,6 +647,15 @@ Server.prototype.register = function(name, handler, serialize, deserialize, return true; }; +/** + * Add a service to the server, with a corresponding implementation. If you are + * generating this from a proto file, you should instead use + * addProtoService. + * @param {Object<String, *>} service The service descriptor, as + * {@link module:src/common.getProtobufServiceAttrs} returns + * @param {Object<String, function>} implementation Map of method names to + * method implementation for the provided service. + */ Server.prototype.addService = function(service, implementation) { if (this.started) { throw new Error('Can\'t add a service to a started server.'); @@ -642,6 +693,12 @@ Server.prototype.addService = function(service, implementation) { }); }; +/** + * Add a proto service to the server, with a corresponding implementation + * @param {Protobuf.Reflect.Service} service The proto service descriptor + * @param {Object<String, function>} implementation Map of method names to + * method implementation for the provided service. + */ Server.prototype.addProtoService = function(service, implementation) { this.addService(common.getProtobufServiceAttrs(service), implementation); }; @@ -665,6 +722,6 @@ Server.prototype.bind = function(port, creds) { }; /** - * See documentation for Server + * @see module:src/server~Server */ exports.Server = Server; diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js index 98158ffff3..942c31ac68 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(); }); }); @@ -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 33200c99ee..3e61d3bbc6 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/end_to_end_test.js b/src/node/test/end_to_end_test.js index 667852f382..5d3baf823d 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(); }); diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js index 7cb34fa0cb..9c7bb465aa 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/node/test/surface_test.js b/src/node/test/surface_test.js index 1dbe4e2805..98f9b15bfc 100644 --- a/src/node/test/surface_test.js +++ b/src/node/test/surface_test.js @@ -343,6 +343,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]); @@ -548,6 +551,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; diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m index d27f7ca565..8518f78c5b 100644 --- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m @@ -38,7 +38,7 @@ @implementation GRPCUnsecuredChannel - (instancetype)initWithHost:(NSString *)host { - return (self = [super initWithChannel:grpc_channel_create(host.UTF8String, NULL)]); + return (self = [super initWithChannel:grpc_insecure_channel_create(host.UTF8String, NULL)]); } @end diff --git a/src/php/composer.json b/src/php/composer.json index b0115bdadd..2d0fe0c87a 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/ext/grpc/call.c b/src/php/ext/grpc/call.c index b67bae7568..1f76c7359d 100644 --- a/src/php/ext/grpc/call.c +++ b/src/php/ext/grpc/call.c @@ -473,6 +473,16 @@ cleanup: } /** + * Get the endpoint this call/stream is connected to + * @return string The URI of the endpoint + */ +PHP_METHOD(Call, getPeer) { + wrapped_grpc_call *call = + (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC); + RETURN_STRING(grpc_call_get_peer(call->wrapped), 1); +} + +/** * Cancel the call. This will cause the call to end with STATUS_CANCELLED if it * has not already ended with another status. */ @@ -485,7 +495,9 @@ PHP_METHOD(Call, cancel) { static zend_function_entry call_methods[] = { PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(Call, startBatch, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC) PHP_FE_END}; + PHP_ME(Call, getPeer, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC) + PHP_FE_END}; void grpc_init_call(TSRMLS_D) { zend_class_entry ce; diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c index b8262db162..7d8a6f87ab 100644 --- a/src/php/ext/grpc/channel.c +++ b/src/php/ext/grpc/channel.c @@ -152,7 +152,7 @@ PHP_METHOD(Channel, __construct) { override = target; override_len = target_length; if (args_array == NULL) { - channel->wrapped = grpc_channel_create(target, NULL); + channel->wrapped = grpc_insecure_channel_create(target, NULL); } else { array_hash = Z_ARRVAL_P(args_array); if (zend_hash_find(array_hash, "credentials", sizeof("credentials"), @@ -182,7 +182,7 @@ PHP_METHOD(Channel, __construct) { } php_grpc_read_args_array(args_array, &args); if (creds == NULL) { - channel->wrapped = grpc_channel_create(target, &args); + channel->wrapped = grpc_insecure_channel_create(target, &args); } else { gpr_log(GPR_DEBUG, "Initialized secure channel"); channel->wrapped = @@ -195,6 +195,16 @@ PHP_METHOD(Channel, __construct) { } /** + * Get the endpoint this call/stream is connected to + * @return string The URI of the endpoint + */ +PHP_METHOD(Channel, getTarget) { + wrapped_grpc_channel *channel = + (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC); + RETURN_STRING(grpc_channel_get_target(channel->wrapped), 1); +} + +/** * Close the channel */ PHP_METHOD(Channel, close) { @@ -208,7 +218,9 @@ PHP_METHOD(Channel, close) { static zend_function_entry channel_methods[] = { PHP_ME(Channel, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) - PHP_ME(Channel, close, NULL, ZEND_ACC_PUBLIC) PHP_FE_END}; + PHP_ME(Channel, getTarget, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Channel, close, NULL, ZEND_ACC_PUBLIC) + PHP_FE_END}; void grpc_init_channel(TSRMLS_D) { zend_class_entry ce; diff --git a/src/php/ext/grpc/credentials.c b/src/php/ext/grpc/credentials.c index a262b9981f..01cb94e3aa 100644 --- a/src/php/ext/grpc/credentials.c +++ b/src/php/ext/grpc/credentials.c @@ -175,23 +175,12 @@ 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) PHP_ME(Credentials, createSsl, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) 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/php/ext/grpc/server_credentials.c b/src/php/ext/grpc/server_credentials.c index c4c1fabb1a..e9183c4598 100644 --- a/src/php/ext/grpc/server_credentials.c +++ b/src/php/ext/grpc/server_credentials.c @@ -115,27 +115,16 @@ PHP_METHOD(ServerCredentials, createSsl) { "createSsl expects 3 strings", 1 TSRMLS_CC); return; } - grpc_server_credentials *creds = - grpc_ssl_server_credentials_create(pem_root_certs, &pem_key_cert_pair, 1); - zval *creds_object = grpc_php_wrap_server_credentials(creds); - 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(); + /* TODO: add a force_client_auth field in ServerCredentials and pass it as + * the last parameter. */ + grpc_server_credentials *creds = grpc_ssl_server_credentials_create( + pem_root_certs, &pem_key_cert_pair, 1, 0); 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/php/lib/Grpc/AbstractCall.php b/src/php/lib/Grpc/AbstractCall.php index 5b28417a0d..35057224f8 100644 --- a/src/php/lib/Grpc/AbstractCall.php +++ b/src/php/lib/Grpc/AbstractCall.php @@ -68,6 +68,13 @@ abstract class AbstractCall { } /** + * @return string The URI of the endpoint. + */ + public function getPeer() { + return $this->call->getPeer(); + } + + /** * Cancels the call */ public function cancel() { diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php index 48c00977eb..a0c677908c 100755 --- a/src/php/lib/Grpc/BaseStub.php +++ b/src/php/lib/Grpc/BaseStub.php @@ -60,11 +60,21 @@ 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); } /** + * @return string The URI of the endpoint. + */ + public function getTarget() { + return $this->channel->getTarget(); + } + + /** * Close the communication channel associated with this stub */ public function close() { diff --git a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php index 6102aaf0a8..8b7e67f57c 100644 --- a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php +++ b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php @@ -43,7 +43,9 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase { $div_arg = new math\DivArgs(); $div_arg->setDividend(7); $div_arg->setDivisor(4); - list($response, $status) = self::$client->Div($div_arg)->wait(); + $call = self::$client->Div($div_arg); + $this->assertTrue(is_string($call->getPeer())); + list($response, $status) = $call->wait(); $this->assertSame(1, $response->getQuotient()); $this->assertSame(3, $response->getRemainder()); $this->assertSame(\Grpc\STATUS_OK, $status->code); @@ -53,6 +55,7 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase { $fib_arg = new math\FibArgs(); $fib_arg->setLimit(7); $call = self::$client->Fib($fib_arg); + $this->assertTrue(is_string($call->getPeer())); $result_array = iterator_to_array($call->responses()); $extract_num = function($num){ return $num->getNum(); @@ -72,6 +75,7 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase { } }; $call = self::$client->Sum($num_iter()); + $this->assertTrue(is_string($call->getPeer())); list($response, $status) = $call->wait(); $this->assertSame(21, $response->getNum()); $this->assertSame(\Grpc\STATUS_OK, $status->code); @@ -79,6 +83,7 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase { public function testBidiStreaming() { $call = self::$client->DivMany(); + $this->assertTrue(is_string($call->getPeer())); for ($i = 0; $i < 7; $i++) { $div_arg = new math\DivArgs(); $div_arg->setDividend(2 * $i + 1); diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php index 2041577557..44e6242c29 100755 --- a/src/php/tests/interop/interop_client.php +++ b/src/php/tests/interop/interop_client.php @@ -332,10 +332,11 @@ if (in_array($args['test_case'], array( $opts['update_metadata'] = $auth->getUpdateMetadataFunc(); } -$stub = new grpc\testing\TestServiceClient( - new Grpc\BaseStub( - $server_address, - $opts)); +$internal_stub = new Grpc\BaseStub($server_address, $opts); +hardAssert(is_string($internal_stub->getTarget()), + 'Unexpected target URI value'); + +$stub = new grpc\testing\TestServiceClient($internal_stub); echo "Connecting to $server_address\n"; echo "Running test case $args[test_case]\n"; diff --git a/src/php/tests/unit_tests/CallTest.php b/src/php/tests/unit_tests/CallTest.php index 77a2d86ce4..caff15ee11 100755 --- a/src/php/tests/unit_tests/CallTest.php +++ b/src/php/tests/unit_tests/CallTest.php @@ -79,4 +79,8 @@ class CallTest extends PHPUnit_Framework_TestCase{ $result = $this->call->startBatch($batch); $this->assertTrue($result->send_metadata); } + + public function testGetPeer() { + $this->assertTrue(is_string($this->call->getPeer())); + } } diff --git a/src/php/tests/unit_tests/EndToEndTest.php b/src/php/tests/unit_tests/EndToEndTest.php index 2980dca4a7..27e27cdfdf 100755 --- a/src/php/tests/unit_tests/EndToEndTest.php +++ b/src/php/tests/unit_tests/EndToEndTest.php @@ -34,8 +34,8 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{ public function setUp() { $this->server = new Grpc\Server([]); - $port = $this->server->addHttp2Port('0.0.0.0:0'); - $this->channel = new Grpc\Channel('localhost:' . $port, []); + $this->port = $this->server->addHttp2Port('0.0.0.0:0'); + $this->channel = new Grpc\Channel('localhost:' . $this->port, []); $this->server->start(); } @@ -149,4 +149,8 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{ unset($call); unset($server_call); } + + public function testGetTarget() { + $this->assertTrue(is_string($this->channel->getTarget())); + } } diff --git a/src/python/src/grpc/_adapter/_c/types.h b/src/python/src/grpc/_adapter/_c/types.h index 3449f0643f..4e0da4a28a 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/channel.c b/src/python/src/grpc/_adapter/_c/types/channel.c index c235597466..feb256cf00 100644 --- a/src/python/src/grpc/_adapter/_c/types/channel.c +++ b/src/python/src/grpc/_adapter/_c/types/channel.c @@ -104,7 +104,7 @@ Channel *pygrpc_Channel_new( if (creds) { self->c_chan = grpc_secure_channel_create(creds->c_creds, target, &c_args); } else { - self->c_chan = grpc_channel_create(target, &c_args); + self->c_chan = grpc_insecure_channel_create(target, &c_args); } pygrpc_discard_channel_args(c_args); return self; 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 6a4561c060..e314c15324 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} @@ -208,6 +205,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 +217,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); @@ -249,20 +247,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/_adapter/_c/types/server_credentials.c b/src/python/src/grpc/_adapter/_c/types/server_credentials.c index 2e02c8fe81..f6859b79d7 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[] = ""; @@ -131,16 +128,11 @@ ServerCredentials *pygrpc_ServerCredentials_ssl( } self = (ServerCredentials *)type->tp_alloc(type, 0); + /* TODO: Add a force_client_auth parameter in the python object and pass it + here as the last arg. */ self->c_creds = grpc_ssl_server_credentials_create( - root_certs, key_cert_pairs, num_key_cert_pairs); + root_certs, key_cert_pairs, num_key_cert_pairs, 0); gpr_free(key_cert_pairs); 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/utility.c b/src/python/src/grpc/_adapter/_c/utility.c index d9f911a41a..51f3c9be01 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/python/src/grpc/_adapter/_c_test.py b/src/python/src/grpc/_adapter/_c_test.py index 133b124072..fe020e2a9c 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/_adapter/_low_test.py b/src/python/src/grpc/_adapter/_low_test.py index a49cd007bf..9a8edfad0c 100644 --- a/src/python/src/grpc/_adapter/_low_test.py +++ b/src/python/src/grpc/_adapter/_low_test.py @@ -97,7 +97,7 @@ class InsecureServerInsecureClient(unittest.TestCase): CLIENT_METADATA_BIN_VALUE = b'\0'*1000 SERVER_INITIAL_METADATA_KEY = 'init_me_me_me' SERVER_INITIAL_METADATA_VALUE = 'whodawha?' - SERVER_TRAILING_METADATA_KEY = 'California_is_in_a_drought' + SERVER_TRAILING_METADATA_KEY = 'california_is_in_a_drought' SERVER_TRAILING_METADATA_VALUE = 'zomg it is' SERVER_STATUS_CODE = _types.StatusCode.OK SERVER_STATUS_DETAILS = 'our work is never over' diff --git a/src/python/src/grpc/_cython/_cygrpc/credentials.pyx b/src/python/src/grpc/_cython/_cygrpc/credentials.pyx index c14d8844dd..2d74702fbd 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 @@ -152,12 +153,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 +205,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 7db8fbe31c..d065383587 100644 --- a/src/python/src/grpc/_cython/_cygrpc/grpc.pxd +++ b/src/python/src/grpc/_cython/_cygrpc/grpc.pxd @@ -313,11 +313,10 @@ 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) - 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/src/python/src/grpc/_cython/adapter_low.py b/src/python/src/grpc/_cython/adapter_low.py index 7546dd1599..2bb468eece 100644 --- a/src/python/src/grpc/_cython/adapter_low.py +++ b/src/python/src/grpc/_cython/adapter_low.py @@ -72,10 +72,6 @@ class ClientCredentials(object): 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 dcb06f345c..f4d9661580 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 838e1e2254..22d210b16b 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() diff --git a/src/python/src/grpc/_links/_proto_scenarios.py b/src/python/src/grpc/_links/_proto_scenarios.py index ccf3c29782..320c0e0f50 100644 --- a/src/python/src/grpc/_links/_proto_scenarios.py +++ b/src/python/src/grpc/_links/_proto_scenarios.py @@ -33,6 +33,7 @@ import abc import threading from grpc._junkdrawer import math_pb2 +from grpc.framework.common import test_constants class ProtoScenario(object): @@ -219,10 +220,9 @@ class BidirectionallyUnaryScenario(ProtoScenario): class BidirectionallyStreamingScenario(ProtoScenario): """A scenario that transmits no protocol buffers in either direction.""" - _STREAM_LENGTH = 200 _REQUESTS = tuple( math_pb2.DivArgs(dividend=59 + index, divisor=7 + index) - for index in range(_STREAM_LENGTH)) + for index in range(test_constants.STREAM_LENGTH)) def __init__(self): self._lock = threading.Lock() diff --git a/src/python/src/grpc/framework/common/test_constants.py b/src/python/src/grpc/framework/common/test_constants.py index 237b8754ed..3126d0d82c 100644 --- a/src/python/src/grpc/framework/common/test_constants.py +++ b/src/python/src/grpc/framework/common/test_constants.py @@ -35,3 +35,9 @@ SHORT_TIMEOUT = 4 # Absurdly large value for maximum duration in seconds for should-not-time-out # RPCs made during tests. LONG_TIMEOUT = 3000 + +# The number of payloads to transmit in streaming tests. +STREAM_LENGTH = 200 + +# The size of thread pools to use in tests. +POOL_SIZE = 10 diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c index bfb9f6ff01..a7607a83a3 100644 --- a/src/ruby/ext/grpc/rb_call.c +++ b/src/ruby/ext/grpc/rb_call.c @@ -235,8 +235,8 @@ static VALUE grpc_rb_call_set_metadata(VALUE self, VALUE metadata) { */ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) { grpc_metadata_array *md_ary = NULL; - int array_length; - int i; + long array_length; + long i; /* Construct a metadata object from key and value and add it */ TypedData_Get_Struct(md_ary_obj, grpc_metadata_array, diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 9bf1a9f945..0cb6fa2f80 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -146,7 +146,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { target_chars = StringValueCStr(target); grpc_rb_hash_convert_to_channel_args(channel_args, &args); if (credentials == Qnil) { - ch = grpc_channel_create(target_chars, &args); + ch = grpc_insecure_channel_create(target_chars, &args); } else { creds = grpc_rb_get_wrapped_credentials(credentials); ch = grpc_secure_channel_create(creds, target_chars, &args); diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c index 829f825597..327fd1a4fc 100644 --- a/src/ruby/ext/grpc/rb_grpc.c +++ b/src/ruby/ext/grpc/rb_grpc.c @@ -139,7 +139,7 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) { rb_raise(rb_eRangeError, "%f out of Time range", RFLOAT_VALUE(time)); } - t.tv_nsec = (time_t)(d * 1e9 + 0.5); + t.tv_nsec = (int)(d * 1e9 + 0.5); } break; @@ -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 e3a0a5ad80..375a651d24 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; } diff --git a/src/ruby/ext/grpc/rb_server_credentials.c b/src/ruby/ext/grpc/rb_server_credentials.c index 5f40935890..62c211d769 100644 --- a/src/ruby/ext/grpc/rb_server_credentials.c +++ b/src/ruby/ext/grpc/rb_server_credentials.c @@ -176,11 +176,12 @@ static VALUE grpc_rb_server_credentials_init(VALUE self, VALUE pem_root_certs, } key_cert_pair.private_key = RSTRING_PTR(pem_private_key); key_cert_pair.cert_chain = RSTRING_PTR(pem_cert_chain); + /* TODO Add a force_client_auth parameter and pass it here. */ if (pem_root_certs == Qnil) { - creds = grpc_ssl_server_credentials_create(NULL, &key_cert_pair, 1); + creds = grpc_ssl_server_credentials_create(NULL, &key_cert_pair, 1, 0); } else { creds = grpc_ssl_server_credentials_create(RSTRING_PTR(pem_root_certs), - &key_cert_pair, 1); + &key_cert_pair, 1, 0); } if (creds == NULL) { rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why"); |