From d2d0a1184e15c6497b11c4248b335573dd87d459 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 19 Jan 2015 16:07:52 -0800 Subject: Capture :path, and send it separately --- src/core/channel/channel_stack.c | 11 +++++++++++ src/core/channel/channel_stack.h | 2 ++ src/core/channel/http_server_filter.c | 30 ++++++++++++++++++++++++------ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/core/channel/channel_stack.c b/src/core/channel/channel_stack.c index 5ee412bf7d..1320568d23 100644 --- a/src/core/channel/channel_stack.c +++ b/src/core/channel/channel_stack.c @@ -202,6 +202,17 @@ grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem) { static void do_nothing(void *user_data, grpc_op_error error) {} +void grpc_call_element_recv_metadata(grpc_call_element *cur_elem, + grpc_mdelem *mdelem) { + grpc_call_op metadata_op; + metadata_op.type = GRPC_RECV_METADATA; + metadata_op.dir = GRPC_CALL_UP; + metadata_op.done_cb = do_nothing; + metadata_op.user_data = NULL; + metadata_op.data.metadata = grpc_mdelem_ref(mdelem); + grpc_call_next_op(cur_elem, &metadata_op); +} + void grpc_call_element_send_metadata(grpc_call_element *cur_elem, grpc_mdelem *mdelem) { grpc_call_op metadata_op; diff --git a/src/core/channel/channel_stack.h b/src/core/channel/channel_stack.h index eb68102b43..8d3ed0aeed 100644 --- a/src/core/channel/channel_stack.h +++ b/src/core/channel/channel_stack.h @@ -292,6 +292,8 @@ void grpc_call_log_op(char *file, int line, gpr_log_severity severity, void grpc_call_element_send_metadata(grpc_call_element *cur_elem, grpc_mdelem *elem); +void grpc_call_element_recv_metadata(grpc_call_element *cur_elem, + grpc_mdelem *elem); void grpc_call_element_send_cancel(grpc_call_element *cur_elem); #ifdef GRPC_CHANNEL_STACK_TRACE diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c index 19b9606b43..8290ead8a7 100644 --- a/src/core/channel/http_server_filter.c +++ b/src/core/channel/http_server_filter.c @@ -37,10 +37,11 @@ #include typedef struct call_data { - int sent_status; - int seen_scheme; - int seen_method; - int seen_te_trailers; + gpr_uint8 sent_status; + gpr_uint8 seen_scheme; + gpr_uint8 seen_method; + gpr_uint8 seen_te_trailers; + grpc_mdelem *path; } call_data; typedef struct channel_data { @@ -52,6 +53,7 @@ typedef struct channel_data { grpc_mdelem *grpc_scheme; grpc_mdelem *content_type; grpc_mdelem *status; + grpc_mdstr *path_key; } channel_data; /* used to silence 'variable not used' warnings */ @@ -120,6 +122,13 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, grpc_mdelem_unref(op->data.metadata); op->done_cb(op->user_data, GRPC_OP_OK); grpc_call_element_send_cancel(elem); + } else if (op->data.metadata->key == channeld->path_key) { + if (calld->path != NULL) { + gpr_log(GPR_ERROR, "Received :path twice"); + grpc_mdelem_unref(calld->path); + } + calld->path = grpc_mdelem_ref(op->data.metadata); + op->done_cb(op->user_data, GRPC_OP_OK); } else { /* pass the event up */ grpc_call_next_op(elem, op); @@ -129,7 +138,10 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, /* Have we seen the required http2 transport headers? (:method, :scheme, content-type, with :path and :authority covered at the channel level right now) */ - if (calld->seen_method && calld->seen_scheme && calld->seen_te_trailers) { + if (calld->seen_method && calld->seen_scheme && calld->seen_te_trailers && + calld->path) { + grpc_call_element_recv_metadata(elem, calld->path); + calld->path = NULL; grpc_call_next_op(elem, op); } else { if (!calld->seen_method) { @@ -189,6 +201,7 @@ static void init_call_elem(grpc_call_element *elem, ignore_unused(channeld); /* initialize members */ + calld->path = NULL; calld->sent_status = 0; calld->seen_scheme = 0; calld->seen_method = 0; @@ -201,8 +214,11 @@ static void destroy_call_elem(grpc_call_element *elem) { call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; - ignore_unused(calld); ignore_unused(channeld); + + if (calld->path) { + grpc_mdelem_unref(calld->path); + } } /* Constructor for channel_data */ @@ -225,6 +241,7 @@ static void init_channel_elem(grpc_channel_element *elem, 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->content_type = grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc"); } @@ -241,6 +258,7 @@ static void destroy_channel_elem(grpc_channel_element *elem) { grpc_mdelem_unref(channeld->https_scheme); grpc_mdelem_unref(channeld->grpc_scheme); grpc_mdelem_unref(channeld->content_type); + grpc_mdstr_unref(channeld->path_key); } const grpc_channel_filter grpc_http_server_filter = { -- cgit v1.2.3 From 12b533de59e1c1ec81e52a9f51df70b8dfbe77a7 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 19 Jan 2015 20:31:44 -0800 Subject: Make send/recv_metadata take ownership of passed in metadata --- src/core/channel/channel_stack.c | 4 ++-- src/core/channel/http_client_filter.c | 12 ++++++------ src/core/channel/http_server_filter.c | 4 ++-- src/core/security/auth.c | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/core/channel/channel_stack.c b/src/core/channel/channel_stack.c index 1320568d23..c70b565d2b 100644 --- a/src/core/channel/channel_stack.c +++ b/src/core/channel/channel_stack.c @@ -209,7 +209,7 @@ void grpc_call_element_recv_metadata(grpc_call_element *cur_elem, metadata_op.dir = GRPC_CALL_UP; metadata_op.done_cb = do_nothing; metadata_op.user_data = NULL; - metadata_op.data.metadata = grpc_mdelem_ref(mdelem); + metadata_op.data.metadata = mdelem; grpc_call_next_op(cur_elem, &metadata_op); } @@ -220,7 +220,7 @@ void grpc_call_element_send_metadata(grpc_call_element *cur_elem, metadata_op.dir = GRPC_CALL_DOWN; metadata_op.done_cb = do_nothing; metadata_op.user_data = NULL; - metadata_op.data.metadata = grpc_mdelem_ref(mdelem); + metadata_op.data.metadata = mdelem; grpc_call_next_op(cur_elem, &metadata_op); } diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c index b139b72795..1f6f3e0ca3 100644 --- a/src/core/channel/http_client_filter.c +++ b/src/core/channel/http_client_filter.c @@ -67,8 +67,8 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, /* Send : prefixed headers, which have to be before any application * layer headers. */ calld->sent_headers = 1; - grpc_call_element_send_metadata(elem, channeld->method); - grpc_call_element_send_metadata(elem, channeld->scheme); + grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->method)); + grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->scheme)); } grpc_call_next_op(elem, op); break; @@ -76,12 +76,12 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, if (!calld->sent_headers) { /* Send : prefixed headers, if we haven't already */ calld->sent_headers = 1; - grpc_call_element_send_metadata(elem, channeld->method); - grpc_call_element_send_metadata(elem, channeld->scheme); + grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->method)); + grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->scheme)); } /* Send non : prefixed headers */ - grpc_call_element_send_metadata(elem, channeld->te_trailers); - grpc_call_element_send_metadata(elem, channeld->content_type); + grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->te_trailers)); + grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->content_type)); grpc_call_next_op(elem, op); break; default: diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c index 8290ead8a7..87f9f437e6 100644 --- a/src/core/channel/http_server_filter.c +++ b/src/core/channel/http_server_filter.c @@ -127,7 +127,7 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, gpr_log(GPR_ERROR, "Received :path twice"); grpc_mdelem_unref(calld->path); } - calld->path = grpc_mdelem_ref(op->data.metadata); + calld->path = op->data.metadata; op->done_cb(op->user_data, GRPC_OP_OK); } else { /* pass the event up */ @@ -163,7 +163,7 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, if (!calld->sent_status) { calld->sent_status = 1; /* status is reffed by grpc_call_element_send_metadata */ - grpc_call_element_send_metadata(elem, channeld->status); + grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->status)); } grpc_call_next_op(elem, op); break; diff --git a/src/core/security/auth.c b/src/core/security/auth.c index f743b25838..9d0c075bc3 100644 --- a/src/core/security/auth.c +++ b/src/core/security/auth.c @@ -57,7 +57,7 @@ static void on_credentials_metadata(void *user_data, grpc_mdelem **md_elems, grpc_call_element *elem = (grpc_call_element *)user_data; size_t i; for (i = 0; i < num_md; i++) { - grpc_call_element_send_metadata(elem, md_elems[i]); + grpc_call_element_send_metadata(elem, grpc_mdelem_ref(md_elems[i])); } grpc_call_next_op(elem, &((call_data *)elem->call_data)->op); } -- cgit v1.2.3 From 6afe256b5663ec67308e5ed5cac03ccae5dcd340 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 19 Jan 2015 18:04:23 -0800 Subject: Add helpers for SEND_FINISH --- src/core/channel/channel_stack.c | 9 +++++++++ src/core/channel/channel_stack.h | 1 + 2 files changed, 10 insertions(+) diff --git a/src/core/channel/channel_stack.c b/src/core/channel/channel_stack.c index c70b565d2b..2721ed8cfc 100644 --- a/src/core/channel/channel_stack.c +++ b/src/core/channel/channel_stack.c @@ -232,3 +232,12 @@ void grpc_call_element_send_cancel(grpc_call_element *cur_elem) { cancel_op.user_data = NULL; grpc_call_next_op(cur_elem, &cancel_op); } + +void grpc_call_element_send_finish(grpc_call_element *cur_elem) { + grpc_call_op cancel_op; + cancel_op.type = GRPC_SEND_FINISH; + cancel_op.dir = GRPC_CALL_DOWN; + cancel_op.done_cb = do_nothing; + cancel_op.user_data = NULL; + grpc_call_next_op(cur_elem, &cancel_op); +} diff --git a/src/core/channel/channel_stack.h b/src/core/channel/channel_stack.h index 8d3ed0aeed..0bc31ffeaf 100644 --- a/src/core/channel/channel_stack.h +++ b/src/core/channel/channel_stack.h @@ -295,6 +295,7 @@ void grpc_call_element_send_metadata(grpc_call_element *cur_elem, void grpc_call_element_recv_metadata(grpc_call_element *cur_elem, grpc_mdelem *elem); void grpc_call_element_send_cancel(grpc_call_element *cur_elem); +void grpc_call_element_send_finish(grpc_call_element *cur_elem); #ifdef GRPC_CHANNEL_STACK_TRACE #define GRPC_CALL_LOG_OP(sev, elem, op) grpc_call_log_op(sev, elem, op) -- cgit v1.2.3 From c923cd7683ec7c7f43075cacce6b7f1a15aacc54 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 19 Jan 2015 16:14:31 -0800 Subject: Add knowledge of :method GET --- src/core/channel/http_server_filter.c | 40 +++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c index 87f9f437e6..b5eb1ba396 100644 --- a/src/core/channel/http_server_filter.c +++ b/src/core/channel/http_server_filter.c @@ -36,17 +36,24 @@ #include #include +typedef enum { + NOT_RECEIVED, + POST, + GET +} known_method_type; + typedef struct call_data { + known_method_type seen_method; gpr_uint8 sent_status; gpr_uint8 seen_scheme; - gpr_uint8 seen_method; gpr_uint8 seen_te_trailers; grpc_mdelem *path; } call_data; typedef struct channel_data { grpc_mdelem *te_trailers; - grpc_mdelem *method; + grpc_mdelem *method_get; + grpc_mdelem *method_post; grpc_mdelem *http_scheme; grpc_mdelem *https_scheme; /* TODO(klempner): Remove this once we stop using it */ @@ -75,14 +82,17 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, case GRPC_RECV_METADATA: /* Check if it is one of the headers we care about. */ if (op->data.metadata == channeld->te_trailers || - op->data.metadata == channeld->method || + op->data.metadata == channeld->method_get || + op->data.metadata == channeld->method_post || op->data.metadata == channeld->http_scheme || op->data.metadata == channeld->https_scheme || op->data.metadata == channeld->grpc_scheme || op->data.metadata == channeld->content_type) { /* swallow it */ - if (op->data.metadata == channeld->method) { - calld->seen_method = 1; + if (op->data.metadata == channeld->method_get) { + calld->seen_method = GET; + } else if (op->data.metadata == channeld->method_post) { + calld->seen_method = POST; } else if (op->data.metadata->key == channeld->http_scheme->key) { calld->seen_scheme = 1; } else if (op->data.metadata == channeld->te_trailers) { @@ -110,7 +120,7 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, grpc_mdelem_unref(op->data.metadata); op->done_cb(op->user_data, GRPC_OP_OK); } else if (op->data.metadata->key == channeld->te_trailers->key || - op->data.metadata->key == channeld->method->key || + op->data.metadata->key == channeld->method_post->key || op->data.metadata->key == channeld->http_scheme->key || op->data.metadata->key == channeld->content_type->key) { gpr_log(GPR_ERROR, "Invalid %s: header: '%s'", @@ -138,17 +148,19 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, /* Have we seen the required http2 transport headers? (:method, :scheme, content-type, with :path and :authority covered at the channel level right now) */ - if (calld->seen_method && calld->seen_scheme && calld->seen_te_trailers && + if (calld->seen_method == POST && calld->seen_scheme && calld->seen_te_trailers && calld->path) { grpc_call_element_recv_metadata(elem, calld->path); calld->path = NULL; grpc_call_next_op(elem, op); } else { - if (!calld->seen_method) { + if (calld->seen_method == NOT_RECEIVED) { gpr_log(GPR_ERROR, "Missing :method header"); - } else if (!calld->seen_scheme) { + } + if (!calld->seen_scheme) { gpr_log(GPR_ERROR, "Missing :scheme header"); - } else if (!calld->seen_te_trailers) { + } + if (!calld->seen_te_trailers) { gpr_log(GPR_ERROR, "Missing te trailers header"); } /* Error this call out */ @@ -204,7 +216,7 @@ static void init_call_elem(grpc_call_element *elem, calld->path = NULL; calld->sent_status = 0; calld->seen_scheme = 0; - calld->seen_method = 0; + calld->seen_method = NOT_RECEIVED; calld->seen_te_trailers = 0; } @@ -237,7 +249,8 @@ static void init_channel_elem(grpc_channel_element *elem, /* initialize members */ channeld->te_trailers = grpc_mdelem_from_strings(mdctx, "te", "trailers"); channeld->status = grpc_mdelem_from_strings(mdctx, ":status", "200"); - channeld->method = grpc_mdelem_from_strings(mdctx, ":method", "POST"); + channeld->method_post = grpc_mdelem_from_strings(mdctx, ":method", "POST"); + channeld->method_get = grpc_mdelem_from_strings(mdctx, ":method", "GET"); 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"); @@ -253,7 +266,8 @@ static void destroy_channel_elem(grpc_channel_element *elem) { grpc_mdelem_unref(channeld->te_trailers); grpc_mdelem_unref(channeld->status); - grpc_mdelem_unref(channeld->method); + grpc_mdelem_unref(channeld->method_post); + grpc_mdelem_unref(channeld->method_get); grpc_mdelem_unref(channeld->http_scheme); grpc_mdelem_unref(channeld->https_scheme); grpc_mdelem_unref(channeld->grpc_scheme); -- cgit v1.2.3 From ce6e350111ea0bbea5cde5bdd78c4c4b24228695 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 19 Jan 2015 18:04:42 -0800 Subject: Add a simple GET handler --- src/core/channel/http_server_filter.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c index b5eb1ba396..270df0f59b 100644 --- a/src/core/channel/http_server_filter.c +++ b/src/core/channel/http_server_filter.c @@ -66,6 +66,14 @@ typedef struct channel_data { /* used to silence 'variable not used' warnings */ static void ignore_unused(void *ignored) {} +/* Handle 'GET': not technically grpc, so probably a web browser hitting + us */ +static void handle_get(grpc_call_element *elem) { + channel_data *channeld = elem->channel_data; + grpc_call_element_send_metadata(elem, channeld->status); + grpc_call_element_send_finish(elem); +} + /* Called either: - in response to an API call (or similar) from above, to send something - a network event (or similar) from below, to receive something @@ -153,6 +161,8 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, grpc_call_element_recv_metadata(elem, calld->path); calld->path = NULL; grpc_call_next_op(elem, op); + } else if (calld->seen_method == GET) { + handle_get(elem); } else { if (calld->seen_method == NOT_RECEIVED) { gpr_log(GPR_ERROR, "Missing :method header"); -- cgit v1.2.3 From 7cfa2d951d01f6fade7968042e0abdc6ea5bda26 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 19 Jan 2015 15:41:49 -0800 Subject: Allow sending preformatted messages --- src/core/channel/call_op_string.c | 3 +++ src/core/channel/channel_stack.h | 2 ++ src/core/channel/connected_channel.c | 2 ++ 3 files changed, 7 insertions(+) diff --git a/src/core/channel/call_op_string.c b/src/core/channel/call_op_string.c index 9a7838ce2f..e6557cef99 100644 --- a/src/core/channel/call_op_string.c +++ b/src/core/channel/call_op_string.c @@ -112,6 +112,9 @@ char *grpc_call_op_string(grpc_call_op *op) { case GRPC_SEND_MESSAGE: bprintf(&b, "SEND_MESSAGE"); break; + case GRPC_SEND_PREFORMATTED_MESSAGE: + bprintf(&b, "SEND_PREFORMATTED_MESSAGE"); + break; case GRPC_SEND_FINISH: bprintf(&b, "SEND_FINISH"); break; diff --git a/src/core/channel/channel_stack.h b/src/core/channel/channel_stack.h index 0bc31ffeaf..754e16f4ff 100644 --- a/src/core/channel/channel_stack.h +++ b/src/core/channel/channel_stack.h @@ -69,6 +69,8 @@ typedef enum { GRPC_SEND_START, /* send a message to the channels peer */ GRPC_SEND_MESSAGE, + /* send a pre-formatted message to the channels peer */ + GRPC_SEND_PREFORMATTED_MESSAGE, /* send half-close to the channels peer */ GRPC_SEND_FINISH, /* request that more data be allowed through flow control */ diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c index e01cb81a89..6067896a8c 100644 --- a/src/core/channel/connected_channel.c +++ b/src/core/channel/connected_channel.c @@ -140,6 +140,8 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, grpc_sopb_add_begin_message(&calld->outgoing_sopb, grpc_byte_buffer_length(op->data.message), op->flags); + /* fall-through */ + case GRPC_SEND_PREFORMATTED_MESSAGE: copy_byte_buffer_to_stream_ops(op->data.message, &calld->outgoing_sopb); calld->outgoing_buffer_length_estimate += (5 + grpc_byte_buffer_length(op->data.message)); -- cgit v1.2.3 From c50e398d6582da7d2bbe2484201ef4900b68e0d1 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 20 Jan 2015 16:30:54 -0800 Subject: First pass API for serving static data --- include/grpc/grpc_http.h | 53 +++++++++++++++++++++++++++++++++++ src/core/channel/http_server_filter.c | 31 ++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 include/grpc/grpc_http.h diff --git a/include/grpc/grpc_http.h b/include/grpc/grpc_http.h new file mode 100644 index 0000000000..a025f8607d --- /dev/null +++ b/include/grpc/grpc_http.h @@ -0,0 +1,53 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __GRPC_GRPC_HTTP_H__ +#define __GRPC_GRPC_HTTP_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + const char *path; + const char *content_type; + const char *content; +} grpc_http_server_page; + +#define GRPC_ARG_SERVE_OVER_HTTP "grpc.serve_over_http" + +#ifdef __cplusplus +} +#endif + +#endif /* __GRPC_GRPC_HTTP_H__ */ diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c index 270df0f59b..aef001b7cd 100644 --- a/src/core/channel/http_server_filter.c +++ b/src/core/channel/http_server_filter.c @@ -34,6 +34,8 @@ #include "src/core/channel/http_server_filter.h" #include +#include +#include #include typedef enum { @@ -42,6 +44,12 @@ typedef enum { GET } known_method_type; +typedef struct { + grpc_mdelem *path; + grpc_mdelem *content_type; + grpc_byte_buffer *content; +} gettable; + typedef struct call_data { known_method_type seen_method; gpr_uint8 sent_status; @@ -61,6 +69,9 @@ typedef struct channel_data { grpc_mdelem *content_type; grpc_mdelem *status; grpc_mdstr *path_key; + + size_t gettable_count; + gettable *gettables; } channel_data; /* used to silence 'variable not used' warnings */ @@ -247,6 +258,9 @@ static void destroy_call_elem(grpc_call_element *elem) { static void init_channel_elem(grpc_channel_element *elem, const grpc_channel_args *args, grpc_mdctx *mdctx, int is_first, int is_last) { + size_t i; + size_t gettable_capacity = 0; + /* grab pointers to our data from the channel element */ channel_data *channeld = elem->channel_data; @@ -267,6 +281,23 @@ static void init_channel_elem(grpc_channel_element *elem, channeld->path_key = grpc_mdstr_from_string(mdctx, ":path"); channeld->content_type = grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc"); + + for (i = 0; i < args->num_args; i++) { + if (0 == strcmp(args->args[i].key, GRPC_ARG_SERVE_OVER_HTTP)) { + gettable *g; + gpr_slice slice; + grpc_http_server_page *p = args->args[i].value.pointer.p; + if (channeld->gettable_count == gettable_capacity) { + gettable_capacity = GPR_MAX(gettable_capacity * 3 / 2, gettable_capacity + 1); + channeld->gettables = gpr_realloc(channeld->gettables, gettable_capacity); + } + g = &channeld->gettables[channeld->gettable_count++]; + g->path = grpc_mdelem_from_strings(mdctx, ":path", p->path); + g->content_type = grpc_mdelem_from_strings(mdctx, "content-type", p->content_type); + slice = gpr_slice_from_copied_string(p->content); + g->content = grpc_byte_buffer_create(&slice, 1); + } + } } /* Destructor for channel data */ -- cgit v1.2.3 From 8a84be382ad937c7227505ba5516363f82c5f59e Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 21 Jan 2015 12:29:41 -0800 Subject: Echo server gets security --- test/core/echo/server.c | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/test/core/echo/server.c b/test/core/echo/server.c index 35f118dc9b..590cb681ac 100644 --- a/test/core/echo/server.c +++ b/test/core/echo/server.c @@ -32,6 +32,7 @@ */ #include +#include #include #include @@ -41,11 +42,13 @@ #include "test/core/util/test_config.h" #include +#include #include #include #include #include #include "test/core/util/port.h" +#include "test/core/end2end/data/ssl_test_data.h" static grpc_completion_queue *cq; static grpc_server *server; @@ -83,29 +86,53 @@ static void sigint_handler(int x) { got_sigint = 1; } int main(int argc, char **argv) { grpc_event *ev; - char *addr; call_state *s; + char *addr_buf = NULL; + gpr_cmdline *cl; int shutdown_started = 0; int shutdown_finished = 0; - grpc_test_init(argc, argv); + int secure = 0; + char *addr = NULL; + + char *fake_argv[1]; + + GPR_ASSERT(argc >= 1); + fake_argv[0] = argv[0]; + grpc_test_init(1, fake_argv); grpc_init(); srand(clock()); - if (argc == 2) { - addr = gpr_strdup(argv[1]); - } else { - gpr_join_host_port(&addr, "::", grpc_pick_unused_port_or_die()); + cl = gpr_cmdline_create("echo server"); + gpr_cmdline_add_string(cl, "bind", "Bind host:port", &addr); + gpr_cmdline_add_flag(cl, "secure", "Run with security?", &secure); + gpr_cmdline_parse(cl, argc, argv); + gpr_cmdline_destroy(cl); + + if (addr == NULL) { + gpr_join_host_port(&addr_buf, "::", grpc_pick_unused_port_or_die()); + addr = addr_buf; } gpr_log(GPR_INFO, "creating server on: %s", addr); cq = grpc_completion_queue_create(); - server = grpc_server_create(cq, NULL); - GPR_ASSERT(grpc_server_add_http2_port(server, addr)); - gpr_free(addr); + if (secure) { + grpc_server_credentials *ssl_creds = grpc_ssl_server_credentials_create( + NULL, 0, test_server1_key, test_server1_key_size, test_server1_cert, + test_server1_cert_size); + server = grpc_secure_server_create(ssl_creds, cq, NULL); + GPR_ASSERT(grpc_server_add_secure_http2_port(server, addr)); + grpc_server_credentials_release(ssl_creds); + } else { + server = grpc_server_create(cq, NULL); + GPR_ASSERT(grpc_server_add_http2_port(server, addr)); + } grpc_server_start(server); + gpr_free(addr_buf); + addr = addr_buf = NULL; + request_call(); signal(SIGINT, sigint_handler); -- cgit v1.2.3 From c6dffe5c5172bc4d8f98980b561dd77d9f631876 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 21 Jan 2015 13:00:10 -0800 Subject: Allow null copy/destroy functions --- src/core/channel/channel_args.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/channel/channel_args.c b/src/core/channel/channel_args.c index 36312e54de..7ba5fbc9d9 100644 --- a/src/core/channel/channel_args.c +++ b/src/core/channel/channel_args.c @@ -52,7 +52,7 @@ static grpc_arg copy_arg(const grpc_arg *src) { break; case GRPC_ARG_POINTER: dst.value.pointer = src->value.pointer; - dst.value.pointer.p = src->value.pointer.copy(src->value.pointer.p); + dst.value.pointer.p = src->value.pointer.copy? src->value.pointer.copy(src->value.pointer.p) : src->value.pointer.p; break; } return dst; @@ -91,7 +91,9 @@ void grpc_channel_args_destroy(grpc_channel_args *a) { case GRPC_ARG_INTEGER: break; case GRPC_ARG_POINTER: - a->args[i].value.pointer.destroy(a->args[i].value.pointer.p); + if (a->args[i].value.pointer.destroy) { + a->args[i].value.pointer.destroy(a->args[i].value.pointer.p); + } break; } gpr_free(a->args[i].key); -- cgit v1.2.3 From 53d5f9d887ae50d255a96536b8555b32631d4489 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 21 Jan 2015 13:03:18 -0800 Subject: Initialize some members --- src/core/channel/http_server_filter.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c index aef001b7cd..e6f88a4bd4 100644 --- a/src/core/channel/http_server_filter.c +++ b/src/core/channel/http_server_filter.c @@ -282,6 +282,9 @@ static void init_channel_elem(grpc_channel_element *elem, channeld->content_type = grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc"); + /* initialize http download support */ + channeld->gettable_count = 0; + channeld->gettables = NULL; for (i = 0; i < args->num_args; i++) { if (0 == strcmp(args->args[i].key, GRPC_ARG_SERVE_OVER_HTTP)) { gettable *g; -- cgit v1.2.3 From fd7d3ec0392a1f39c9a826c29001dd32a45d99f6 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 21 Jan 2015 13:37:09 -0800 Subject: Actually serve up content --- src/core/channel/http_server_filter.c | 72 ++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c index e6f88a4bd4..bb676a4068 100644 --- a/src/core/channel/http_server_filter.c +++ b/src/core/channel/http_server_filter.c @@ -38,11 +38,7 @@ #include #include -typedef enum { - NOT_RECEIVED, - POST, - GET -} known_method_type; +typedef enum { NOT_RECEIVED, POST, GET } known_method_type; typedef struct { grpc_mdelem *path; @@ -67,7 +63,8 @@ typedef struct channel_data { /* TODO(klempner): Remove this once we stop using it */ grpc_mdelem *grpc_scheme; grpc_mdelem *content_type; - grpc_mdelem *status; + grpc_mdelem *status_ok; + grpc_mdelem *status_not_found; grpc_mdstr *path_key; size_t gettable_count; @@ -79,9 +76,35 @@ static void ignore_unused(void *ignored) {} /* Handle 'GET': not technically grpc, so probably a web browser hitting us */ +static void payload_done(void *elem, grpc_op_error error) { + if (error == GRPC_OP_OK) { + grpc_call_element_send_finish(elem); + } +} + static void handle_get(grpc_call_element *elem) { channel_data *channeld = elem->channel_data; - grpc_call_element_send_metadata(elem, channeld->status); + call_data *calld = elem->call_data; + grpc_call_op op; + size_t i; + + for (i = 0; i < channeld->gettable_count; i++) { + if (channeld->gettables[i].path == calld->path) { + grpc_call_element_send_metadata(elem, + grpc_mdelem_ref(channeld->status_ok)); + grpc_call_element_send_metadata( + elem, grpc_mdelem_ref(channeld->gettables[i].content_type)); + op.type = GRPC_SEND_PREFORMATTED_MESSAGE; + op.dir = GRPC_CALL_DOWN; + op.flags = 0; + op.data.message = channeld->gettables[i].content; + op.done_cb = payload_done; + op.user_data = elem; + grpc_call_next_op(elem, &op); + } + } + grpc_call_element_send_metadata(elem, + grpc_mdelem_ref(channeld->status_not_found)); grpc_call_element_send_finish(elem); } @@ -167,8 +190,8 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, /* Have we seen the required http2 transport headers? (:method, :scheme, content-type, with :path and :authority covered at the channel level right now) */ - if (calld->seen_method == POST && calld->seen_scheme && calld->seen_te_trailers && - calld->path) { + if (calld->seen_method == POST && calld->seen_scheme && + calld->seen_te_trailers && calld->path) { grpc_call_element_recv_metadata(elem, calld->path); calld->path = NULL; grpc_call_next_op(elem, op); @@ -196,7 +219,8 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, if (!calld->sent_status) { calld->sent_status = 1; /* status is reffed by grpc_call_element_send_metadata */ - grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->status)); + grpc_call_element_send_metadata(elem, + grpc_mdelem_ref(channeld->status_ok)); } grpc_call_next_op(elem, op); break; @@ -272,7 +296,9 @@ static void init_channel_elem(grpc_channel_element *elem, /* initialize members */ channeld->te_trailers = grpc_mdelem_from_strings(mdctx, "te", "trailers"); - channeld->status = grpc_mdelem_from_strings(mdctx, ":status", "200"); + channeld->status_ok = grpc_mdelem_from_strings(mdctx, ":status", "200"); + channeld->status_not_found = + grpc_mdelem_from_strings(mdctx, ":status", "404"); channeld->method_post = grpc_mdelem_from_strings(mdctx, ":method", "POST"); channeld->method_get = grpc_mdelem_from_strings(mdctx, ":method", "GET"); channeld->http_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "http"); @@ -281,7 +307,7 @@ static void init_channel_elem(grpc_channel_element *elem, channeld->path_key = grpc_mdstr_from_string(mdctx, ":path"); channeld->content_type = grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc"); - + /* initialize http download support */ channeld->gettable_count = 0; channeld->gettables = NULL; @@ -291,12 +317,15 @@ static void init_channel_elem(grpc_channel_element *elem, gpr_slice slice; grpc_http_server_page *p = args->args[i].value.pointer.p; if (channeld->gettable_count == gettable_capacity) { - gettable_capacity = GPR_MAX(gettable_capacity * 3 / 2, gettable_capacity + 1); - channeld->gettables = gpr_realloc(channeld->gettables, gettable_capacity); + gettable_capacity = + GPR_MAX(gettable_capacity * 3 / 2, gettable_capacity + 1); + channeld->gettables = + gpr_realloc(channeld->gettables, gettable_capacity); } g = &channeld->gettables[channeld->gettable_count++]; g->path = grpc_mdelem_from_strings(mdctx, ":path", p->path); - g->content_type = grpc_mdelem_from_strings(mdctx, "content-type", p->content_type); + g->content_type = + grpc_mdelem_from_strings(mdctx, "content-type", p->content_type); slice = gpr_slice_from_copied_string(p->content); g->content = grpc_byte_buffer_create(&slice, 1); } @@ -309,7 +338,8 @@ static void destroy_channel_elem(grpc_channel_element *elem) { channel_data *channeld = elem->channel_data; grpc_mdelem_unref(channeld->te_trailers); - grpc_mdelem_unref(channeld->status); + grpc_mdelem_unref(channeld->status_ok); + grpc_mdelem_unref(channeld->status_not_found); grpc_mdelem_unref(channeld->method_post); grpc_mdelem_unref(channeld->method_get); grpc_mdelem_unref(channeld->http_scheme); @@ -320,10 +350,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_http_server_filter = { - call_op, channel_op, - - sizeof(call_data), init_call_elem, destroy_call_elem, - - sizeof(channel_data), init_channel_elem, destroy_channel_elem, - - "http-server"}; + call_op, channel_op, sizeof(call_data), + init_call_elem, destroy_call_elem, sizeof(channel_data), + init_channel_elem, destroy_channel_elem, "http-server"}; -- cgit v1.2.3 From 3948412b15672834ba099756cf9bf62ddc06ac78 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 21 Jan 2015 13:37:23 -0800 Subject: Have echo server serve up some html --- test/core/echo/server.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/test/core/echo/server.c b/test/core/echo/server.c index 590cb681ac..ee8058ebf5 100644 --- a/test/core/echo/server.c +++ b/test/core/echo/server.c @@ -32,6 +32,7 @@ */ #include +#include #include #include @@ -97,12 +98,27 @@ int main(int argc, char **argv) { char *fake_argv[1]; +#define MAX_ARGS 4 + grpc_arg arge[MAX_ARGS]; + grpc_arg *e; + grpc_channel_args args = {0, NULL}; + + grpc_http_server_page home_page = {"/", "text/html", + "\n" + "Echo Server\n" + "\n" + "\n" + "Welcome to the world of the future!\n" + "\n"}; + GPR_ASSERT(argc >= 1); fake_argv[0] = argv[0]; grpc_test_init(1, fake_argv); grpc_init(); srand(clock()); + memset(arge, 0, sizeof(arge)); + args.args = arge; cl = gpr_cmdline_create("echo server"); gpr_cmdline_add_string(cl, "bind", "Bind host:port", &addr); @@ -110,6 +126,11 @@ int main(int argc, char **argv) { gpr_cmdline_parse(cl, argc, argv); gpr_cmdline_destroy(cl); + e = &arge[args.num_args++]; + e->type = GRPC_ARG_POINTER; + e->key = GRPC_ARG_SERVE_OVER_HTTP; + e->value.pointer.p = &home_page; + if (addr == NULL) { gpr_join_host_port(&addr_buf, "::", grpc_pick_unused_port_or_die()); addr = addr_buf; @@ -121,7 +142,7 @@ int main(int argc, char **argv) { grpc_server_credentials *ssl_creds = grpc_ssl_server_credentials_create( NULL, 0, test_server1_key, test_server1_key_size, test_server1_cert, test_server1_cert_size); - server = grpc_secure_server_create(ssl_creds, cq, NULL); + server = grpc_secure_server_create(ssl_creds, cq, &args); GPR_ASSERT(grpc_server_add_secure_http2_port(server, addr)); grpc_server_credentials_release(ssl_creds); } else { -- cgit v1.2.3 From b7e0cb56bed6ba18a28ce4bc4013dc667d485781 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 21 Jan 2015 13:41:30 -0800 Subject: Allocate the correct amount of memory --- src/core/channel/http_server_filter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c index bb676a4068..2658a6d42e 100644 --- a/src/core/channel/http_server_filter.c +++ b/src/core/channel/http_server_filter.c @@ -320,7 +320,7 @@ static void init_channel_elem(grpc_channel_element *elem, gettable_capacity = GPR_MAX(gettable_capacity * 3 / 2, gettable_capacity + 1); channeld->gettables = - gpr_realloc(channeld->gettables, gettable_capacity); + gpr_realloc(channeld->gettables, gettable_capacity * sizeof(gettable)); } g = &channeld->gettables[channeld->gettable_count++]; g->path = grpc_mdelem_from_strings(mdctx, ":path", p->path); -- cgit v1.2.3 From faadd2386c8ab7cf15347cfd2131d4c26a6abdc2 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 21 Jan 2015 14:01:19 -0800 Subject: Add some documentation --- include/grpc/grpc_http.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/grpc/grpc_http.h b/include/grpc/grpc_http.h index a025f8607d..b2ae5340a5 100644 --- a/include/grpc/grpc_http.h +++ b/include/grpc/grpc_http.h @@ -38,6 +38,20 @@ extern "C" { #endif +/* HTTP GET support. + + HTTP2 servers can publish statically generated text content served + via HTTP2 GET queries by publishing one or more grpc_http_server_page + elements via repeated GRPC_ARG_SERVE_OVER_HTTP elements in the servers + channel_args. + + This is not: + - a general purpose web server + - particularly fast + + It's useful for being able to serve up some static content (maybe some + javascript to be able to interact with your GRPC server?) */ + typedef struct { const char *path; const char *content_type; -- cgit v1.2.3 From 59963419c4a0448c10122bed4de0e4a1eac6c005 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 21 Jan 2015 14:04:01 -0800 Subject: Clean up formatting --- test/core/echo/server.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/core/echo/server.c b/test/core/echo/server.c index ee8058ebf5..93feba2668 100644 --- a/test/core/echo/server.c +++ b/test/core/echo/server.c @@ -104,12 +104,12 @@ int main(int argc, char **argv) { grpc_channel_args args = {0, NULL}; grpc_http_server_page home_page = {"/", "text/html", - "\n" - "Echo Server\n" - "\n" - "\n" - "Welcome to the world of the future!\n" - "\n"}; + "\n" + "Echo Server\n" + "\n" + "\n" + "Welcome to the world of the future!\n" + "\n"}; GPR_ASSERT(argc >= 1); fake_argv[0] = argv[0]; -- cgit v1.2.3 From 0a2077176524ae08eeb02fcd63f1e3e28a715741 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 08:12:38 -0800 Subject: Update to the latest security API --- test/core/echo/server.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/core/echo/server.c b/test/core/echo/server.c index 93feba2668..c20260884b 100644 --- a/test/core/echo/server.c +++ b/test/core/echo/server.c @@ -139,10 +139,11 @@ int main(int argc, char **argv) { cq = grpc_completion_queue_create(); if (secure) { - grpc_server_credentials *ssl_creds = grpc_ssl_server_credentials_create( - NULL, 0, test_server1_key, test_server1_key_size, test_server1_cert, - test_server1_cert_size); - server = grpc_secure_server_create(ssl_creds, cq, &args); + grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {test_server1_key, + test_server1_cert}; + grpc_server_credentials *ssl_creds = + grpc_ssl_server_credentials_create(NULL, &pem_key_cert_pair, 1); + server = grpc_secure_server_create(ssl_creds, cq, NULL); GPR_ASSERT(grpc_server_add_secure_http2_port(server, addr)); grpc_server_credentials_release(ssl_creds); } else { -- cgit v1.2.3 From 94022a765aaa5af004f20af698696e3af643445d Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 08:18:47 -0800 Subject: clang-format --- src/core/channel/channel_args.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/channel/channel_args.c b/src/core/channel/channel_args.c index 7ba5fbc9d9..c1ab698012 100644 --- a/src/core/channel/channel_args.c +++ b/src/core/channel/channel_args.c @@ -52,7 +52,9 @@ static grpc_arg copy_arg(const grpc_arg *src) { break; case GRPC_ARG_POINTER: dst.value.pointer = src->value.pointer; - dst.value.pointer.p = src->value.pointer.copy? src->value.pointer.copy(src->value.pointer.p) : src->value.pointer.p; + dst.value.pointer.p = src->value.pointer.copy + ? src->value.pointer.copy(src->value.pointer.p) + : src->value.pointer.p; break; } return dst; -- cgit v1.2.3 From 66a1c08e6b975d38d92c9ce79b51f9f6658d2438 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 13:31:59 -0800 Subject: Utilities for concatenating many strings --- src/core/support/string.c | 43 +++++++++++++++++++++++++++++++++++++++++++ src/core/support/string.h | 15 +++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/src/core/support/string.c b/src/core/support/string.c index 9b5cac7596..87c2cd351b 100644 --- a/src/core/support/string.c +++ b/src/core/support/string.c @@ -152,3 +152,46 @@ int gpr_ltoa(long value, char *string) { string[i] = 0; return i; } + +char *gpr_strjoin(const char **strs, size_t nstrs) { + size_t out_length = 0; + size_t i; + char *out; + for (i = 0; i < nstrs; i++) { + out_length += strlen(strs[i]); + } + out_length += 1; /* null terminator */ + out = gpr_malloc(out_length); + out_length = 0; + for (i = 0; i < nstrs; i++) { + size_t slen = strlen(strs[i]); + memcpy(out + out_length, strs[i], slen); + out_length += slen; + } + out[out_length] = 0; + return out; +} + +void gpr_strvec_init(gpr_strvec *sv) { + memset(sv, 0, sizeof(*sv)); +} + +void gpr_strvec_destroy(gpr_strvec *sv) { + size_t i; + for (i = 0; i < sv->count; i++) { + gpr_free(sv->strs[i]); + } + gpr_free(sv->strs); +} + +void gpr_strvec_add(gpr_strvec *sv, char *str) { + if (sv->count == sv->capacity) { + sv->capacity = GPR_MAX(sv->capacity + 8, sv->capacity * 3 / 2); + sv->strs = gpr_realloc(sv->strs, sizeof(char*) * sv->capacity); + } + sv->strs[sv->count++] = str; +} + +char *gpr_strvec_flatten(gpr_strvec *sv) { + return gpr_strjoin((const char**)sv->strs, sv->count); +} diff --git a/src/core/support/string.h b/src/core/support/string.h index 71bd3f84e3..f2bf8c1c3a 100644 --- a/src/core/support/string.h +++ b/src/core/support/string.h @@ -80,6 +80,21 @@ void gpr_reverse_bytes(char *str, int len); the result is undefined. */ int gpr_asprintf(char **strp, const char *format, ...); +/* Join a set of strings, returning the resulting string */ +char *gpr_strjoin(const char **strs, size_t nstrs); + +/* A vector of strings... addition takes ownership of strings */ +typedef struct { + char **strs; + size_t count; + size_t capacity; +} gpr_strvec; + +void gpr_strvec_init(gpr_strvec *strs); +void gpr_strvec_destroy(gpr_strvec *strs); +void gpr_strvec_add(gpr_strvec *strs, char *add); +char *gpr_strvec_flatten(gpr_strvec *strs); + #ifdef __cplusplus } #endif -- cgit v1.2.3 From d4c18706757c3a88f802265e839c98dda2d799e0 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 13:40:56 -0800 Subject: Remove uses of sprintf --- src/core/surface/event_string.c | 80 ++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/src/core/surface/event_string.c b/src/core/surface/event_string.c index e38ef06c9f..5a71cdadab 100644 --- a/src/core/surface/event_string.c +++ b/src/core/surface/event_string.c @@ -38,8 +38,10 @@ #include "src/core/support/string.h" #include -static size_t addhdr(char *p, grpc_event *ev) { - return sprintf(p, "tag:%p call:%p", ev->tag, (void *)ev->call); +static void addhdr(gpr_strvec *buf, grpc_event *ev) { + char *tmp; + gpr_asprintf(&tmp, "tag:%p call:%p", ev->tag, (void *)ev->call); + gpr_strvec_add(buf, tmp); } static const char *errstr(grpc_op_error err) { @@ -52,72 +54,84 @@ static const char *errstr(grpc_op_error err) { return "UNKNOWN_UNKNOWN"; } -static size_t adderr(char *p, grpc_op_error err) { - return sprintf(p, " err=%s", errstr(err)); +static void adderr(gpr_strvec *buf, grpc_op_error err) { + char *tmp; + gpr_asprintf(&tmp, " err=%s", errstr(err)); + gpr_strvec_add(buf, tmp); } char *grpc_event_string(grpc_event *ev) { - char buffer[1024]; - char *p = buffer; + char *out; + char *tmp; + gpr_strvec buf; if (ev == NULL) return gpr_strdup("null"); + gpr_strvec_init(&buf); + switch (ev->type) { case GRPC_SERVER_SHUTDOWN: - p += sprintf(p, "SERVER_SHUTDOWN"); + gpr_strvec_add(&buf, gpr_strdup("SERVER_SHUTDOWN")); break; case GRPC_QUEUE_SHUTDOWN: - p += sprintf(p, "QUEUE_SHUTDOWN"); + gpr_strvec_add(&buf, gpr_strdup("QUEUE_SHUTDOWN")); break; case GRPC_READ: - p += sprintf(p, "READ: "); - p += addhdr(p, ev); + gpr_strvec_add(&buf, gpr_strdup("READ: ")); + addhdr(&buf, ev); if (ev->data.read) { - p += sprintf(p, " %d bytes", + gpr_asprintf(&tmp, " %d bytes", (int)grpc_byte_buffer_length(ev->data.read)); + gpr_strvec_add(&buf, tmp); } else { - p += sprintf(p, " end-of-stream"); + gpr_strvec_add(&buf, gpr_strdup(" end-of-stream")); } break; case GRPC_INVOKE_ACCEPTED: - p += sprintf(p, "INVOKE_ACCEPTED: "); - p += addhdr(p, ev); - p += adderr(p, ev->data.invoke_accepted); + gpr_strvec_add(&buf, gpr_strdup("INVOKE_ACCEPTED: ")); + addhdr(&buf, ev); + adderr(&buf, ev->data.invoke_accepted); break; case GRPC_WRITE_ACCEPTED: - p += sprintf(p, "WRITE_ACCEPTED: "); - p += addhdr(p, ev); - p += adderr(p, ev->data.write_accepted); + gpr_strvec_add(&buf, gpr_strdup("WRITE_ACCEPTED: ")); + addhdr(&buf, ev); + adderr(&buf, ev->data.write_accepted); break; case GRPC_FINISH_ACCEPTED: - p += sprintf(p, "FINISH_ACCEPTED: "); - p += addhdr(p, ev); - p += adderr(p, ev->data.write_accepted); + gpr_strvec_add(&buf, gpr_strdup("FINISH_ACCEPTED: ")); + addhdr(&buf, ev); + adderr(&buf, ev->data.write_accepted); break; case GRPC_CLIENT_METADATA_READ: - p += sprintf(p, "CLIENT_METADATA_READ: "); - p += addhdr(p, ev); - p += sprintf(p, " %d elements", (int)ev->data.client_metadata_read.count); + gpr_strvec_add(&buf, gpr_strdup("CLIENT_METADATA_READ: ")); + addhdr(&buf, ev); + gpr_asprintf(&tmp, " %d elements", + (int)ev->data.client_metadata_read.count); + gpr_strvec_add(&buf, tmp); break; case GRPC_FINISHED: - p += sprintf(p, "FINISHED: "); - p += addhdr(p, ev); - p += sprintf(p, " status=%d details='%s' %d metadata elements", + gpr_strvec_add(&buf, gpr_strdup("FINISHED: ")); + addhdr(&buf, ev); + gpr_asprintf(&tmp, " status=%d details='%s' %d metadata elements", ev->data.finished.status, ev->data.finished.details, (int)ev->data.finished.metadata_count); + gpr_strvec_add(&buf, tmp); break; case GRPC_SERVER_RPC_NEW: - p += sprintf(p, "SERVER_RPC_NEW: "); - p += addhdr(p, ev); - p += sprintf(p, " method='%s' host='%s' %d metadata elements", + gpr_strvec_add(&buf, gpr_strdup("SERVER_RPC_NEW: ")); + addhdr(&buf, ev); + gpr_asprintf(&tmp, " method='%s' host='%s' %d metadata elements", ev->data.server_rpc_new.method, ev->data.server_rpc_new.host, (int)ev->data.server_rpc_new.metadata_count); + gpr_strvec_add(&buf, tmp); break; case GRPC_COMPLETION_DO_NOT_USE: - p += sprintf(p, "DO_NOT_USE (this is a bug)"); - p += addhdr(p, ev); + gpr_strvec_add(&buf, gpr_strdup("DO_NOT_USE (this is a bug)")); + addhdr(&buf, ev); break; } - return gpr_strdup(buffer); + out = gpr_strvec_flatten(&buf); + gpr_strvec_destroy(&buf); + return out; } -- cgit v1.2.3 From d90e29971ff52e5894f03636744864fce2bee016 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 14:04:16 -0800 Subject: Remove uses of sprintf --- src/core/channel/call_op_string.c | 96 +++++++++++++++------------------------ 1 file changed, 36 insertions(+), 60 deletions(-) diff --git a/src/core/channel/call_op_string.c b/src/core/channel/call_op_string.c index 789913901a..4f19d021d5 100644 --- a/src/core/channel/call_op_string.c +++ b/src/core/channel/call_op_string.c @@ -41,110 +41,86 @@ #include #include -#define MAX_APPEND 1024 +static void put_metadata(gpr_strvec *b, grpc_mdelem *md) { + gpr_strvec_add(b, gpr_strdup(" key=")); + gpr_strvec_add(b, gpr_hexdump((char *)GPR_SLICE_START_PTR(md->key->slice), + GPR_SLICE_LENGTH(md->key->slice), GPR_HEXDUMP_PLAINTEXT)); -typedef struct { - size_t cap; - size_t len; - char *buffer; -} buf; - -static void bprintf(buf *b, const char *fmt, ...) { - va_list arg; - if (b->len + MAX_APPEND > b->cap) { - b->cap = GPR_MAX(b->len + MAX_APPEND, b->cap * 3 / 2); - b->buffer = gpr_realloc(b->buffer, b->cap); - } - va_start(arg, fmt); - b->len += vsprintf(b->buffer + b->len, fmt, arg); - va_end(arg); -} - -static void bputs(buf *b, const char *s) { - size_t slen = strlen(s); - if (b->len + slen + 1 > b->cap) { - b->cap = GPR_MAX(b->len + slen + 1, b->cap * 3 / 2); - b->buffer = gpr_realloc(b->buffer, b->cap); - } - strcat(b->buffer, s); - b->len += slen; -} - -static void put_metadata(buf *b, grpc_mdelem *md) { - char *txt; - - txt = gpr_hexdump((char *)GPR_SLICE_START_PTR(md->key->slice), - GPR_SLICE_LENGTH(md->key->slice), GPR_HEXDUMP_PLAINTEXT); - bputs(b, " key="); - bputs(b, txt); - gpr_free(txt); - - txt = gpr_hexdump((char *)GPR_SLICE_START_PTR(md->value->slice), - GPR_SLICE_LENGTH(md->value->slice), GPR_HEXDUMP_PLAINTEXT); - bputs(b, " value="); - bputs(b, txt); - gpr_free(txt); + gpr_strvec_add(b, gpr_strdup(" value=")); + gpr_strvec_add(b, gpr_hexdump((char *)GPR_SLICE_START_PTR(md->value->slice), + GPR_SLICE_LENGTH(md->value->slice), GPR_HEXDUMP_PLAINTEXT)); } char *grpc_call_op_string(grpc_call_op *op) { - buf b = {0, 0, 0}; + char *tmp; + char *out; + + gpr_strvec b; + gpr_strvec_init(&b); switch (op->dir) { case GRPC_CALL_DOWN: - bprintf(&b, ">"); + gpr_strvec_add(&b, gpr_strdup(">")); break; case GRPC_CALL_UP: - bprintf(&b, "<"); + gpr_strvec_add(&b, gpr_strdup("<")); break; } switch (op->type) { case GRPC_SEND_METADATA: - bprintf(&b, "SEND_METADATA"); + gpr_strvec_add(&b, gpr_strdup("SEND_METADATA")); put_metadata(&b, op->data.metadata); break; case GRPC_SEND_DEADLINE: - bprintf(&b, "SEND_DEADLINE %d.%09d", op->data.deadline.tv_sec, + gpr_asprintf(&tmp, "SEND_DEADLINE %d.%09d", op->data.deadline.tv_sec, op->data.deadline.tv_nsec); + gpr_strvec_add(&b, tmp); break; case GRPC_SEND_START: - bprintf(&b, "SEND_START pollset=%p", op->data.start.pollset); + gpr_asprintf(&tmp, "SEND_START pollset=%p", op->data.start.pollset); + gpr_strvec_add(&b, tmp); break; case GRPC_SEND_MESSAGE: - bprintf(&b, "SEND_MESSAGE"); + gpr_strvec_add(&b, gpr_strdup("SEND_MESSAGE")); break; case GRPC_SEND_FINISH: - bprintf(&b, "SEND_FINISH"); + gpr_strvec_add(&b, gpr_strdup("SEND_FINISH")); break; case GRPC_REQUEST_DATA: - bprintf(&b, "REQUEST_DATA"); + gpr_strvec_add(&b, gpr_strdup("REQUEST_DATA")); break; case GRPC_RECV_METADATA: - bprintf(&b, "RECV_METADATA"); + gpr_strvec_add(&b, gpr_strdup("RECV_METADATA")); put_metadata(&b, op->data.metadata); break; case GRPC_RECV_DEADLINE: - bprintf(&b, "RECV_DEADLINE %d.%09d", op->data.deadline.tv_sec, + gpr_asprintf(&tmp, "RECV_DEADLINE %d.%09d", op->data.deadline.tv_sec, op->data.deadline.tv_nsec); + gpr_strvec_add(&b, tmp); break; case GRPC_RECV_END_OF_INITIAL_METADATA: - bprintf(&b, "RECV_END_OF_INITIAL_METADATA"); + gpr_strvec_add(&b, gpr_strdup("RECV_END_OF_INITIAL_METADATA")); break; case GRPC_RECV_MESSAGE: - bprintf(&b, "RECV_MESSAGE"); + gpr_strvec_add(&b, gpr_strdup("RECV_MESSAGE")); break; case GRPC_RECV_HALF_CLOSE: - bprintf(&b, "RECV_HALF_CLOSE"); + gpr_strvec_add(&b, gpr_strdup("RECV_HALF_CLOSE")); break; case GRPC_RECV_FINISH: - bprintf(&b, "RECV_FINISH"); + gpr_strvec_add(&b, gpr_strdup("RECV_FINISH")); break; case GRPC_CANCEL_OP: - bprintf(&b, "CANCEL_OP"); + gpr_strvec_add(&b, gpr_strdup("CANCEL_OP")); break; } - bprintf(&b, " flags=0x%08x", op->flags); + gpr_asprintf(&tmp, " flags=0x%08x", op->flags); + gpr_strvec_add(&b, tmp); + + out = gpr_strvec_flatten(&b); + gpr_strvec_destroy(&b); - return b.buffer; + return out; } void grpc_call_log_op(char *file, int line, gpr_log_severity severity, -- cgit v1.2.3 From 16ae23dac15a5df861705bd6251b974ae8554a9a Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 14:26:28 -0800 Subject: Add out-param to signal length of buffer --- src/core/channel/call_op_string.c | 2 +- src/core/support/string.c | 9 ++++++--- src/core/support/string.h | 8 +++++--- src/core/surface/event_string.c | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/core/channel/call_op_string.c b/src/core/channel/call_op_string.c index 4f19d021d5..d36d51e789 100644 --- a/src/core/channel/call_op_string.c +++ b/src/core/channel/call_op_string.c @@ -117,7 +117,7 @@ char *grpc_call_op_string(grpc_call_op *op) { gpr_asprintf(&tmp, " flags=0x%08x", op->flags); gpr_strvec_add(&b, tmp); - out = gpr_strvec_flatten(&b); + out = gpr_strvec_flatten(&b, NULL); gpr_strvec_destroy(&b); return out; diff --git a/src/core/support/string.c b/src/core/support/string.c index 87c2cd351b..008b2aac89 100644 --- a/src/core/support/string.c +++ b/src/core/support/string.c @@ -153,7 +153,7 @@ int gpr_ltoa(long value, char *string) { return i; } -char *gpr_strjoin(const char **strs, size_t nstrs) { +char *gpr_strjoin(const char **strs, size_t nstrs, size_t *final_length) { size_t out_length = 0; size_t i; char *out; @@ -169,6 +169,9 @@ char *gpr_strjoin(const char **strs, size_t nstrs) { out_length += slen; } out[out_length] = 0; + if (final_length != NULL) { + *final_length = out_length; + } return out; } @@ -192,6 +195,6 @@ void gpr_strvec_add(gpr_strvec *sv, char *str) { sv->strs[sv->count++] = str; } -char *gpr_strvec_flatten(gpr_strvec *sv) { - return gpr_strjoin((const char**)sv->strs, sv->count); +char *gpr_strvec_flatten(gpr_strvec *sv, size_t *final_length) { + return gpr_strjoin((const char**)sv->strs, sv->count, final_length); } diff --git a/src/core/support/string.h b/src/core/support/string.h index 98c66b14e2..d8fd2638ef 100644 --- a/src/core/support/string.h +++ b/src/core/support/string.h @@ -81,8 +81,10 @@ void gpr_reverse_bytes(char *str, int len); the result is undefined. */ int gpr_asprintf(char **strp, const char *format, ...); -/* Join a set of strings, returning the resulting string */ -char *gpr_strjoin(const char **strs, size_t nstrs); +/* Join a set of strings, returning the resulting string. + Total combined length (excluding null terminator) is returned in total_length + if it is non-null. */ +char *gpr_strjoin(const char **strs, size_t nstrs, size_t *total_length); /* A vector of strings... addition takes ownership of strings */ typedef struct { @@ -94,7 +96,7 @@ typedef struct { void gpr_strvec_init(gpr_strvec *strs); void gpr_strvec_destroy(gpr_strvec *strs); void gpr_strvec_add(gpr_strvec *strs, char *add); -char *gpr_strvec_flatten(gpr_strvec *strs); +char *gpr_strvec_flatten(gpr_strvec *strs, size_t *total_length); #ifdef __cplusplus } diff --git a/src/core/surface/event_string.c b/src/core/surface/event_string.c index 5a71cdadab..8975d312ee 100644 --- a/src/core/surface/event_string.c +++ b/src/core/surface/event_string.c @@ -131,7 +131,7 @@ char *grpc_event_string(grpc_event *ev) { break; } - out = gpr_strvec_flatten(&buf); + out = gpr_strvec_flatten(&buf, NULL); gpr_strvec_destroy(&buf); return out; } -- cgit v1.2.3 From dc4516b18fb84dc35ec6a2b7ab9410cc4bd1dc66 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 14:26:43 -0800 Subject: Remove use of vsprintf --- src/core/httpcli/format_request.c | 82 ++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 44 deletions(-) diff --git a/src/core/httpcli/format_request.c b/src/core/httpcli/format_request.c index 7a44f1266f..58bb7c740e 100644 --- a/src/core/httpcli/format_request.c +++ b/src/core/httpcli/format_request.c @@ -37,67 +37,57 @@ #include #include +#include "src/core/support/string.h" #include #include #include -typedef struct { - size_t length; - size_t capacity; - char *data; -} sbuf; - -static void sbuf_append(sbuf *buf, const char *bytes, size_t len) { - if (buf->length + len > buf->capacity) { - buf->capacity = GPR_MAX(buf->length + len, buf->capacity * 3 / 2); - buf->data = gpr_realloc(buf->data, buf->capacity); - } - memcpy(buf->data + buf->length, bytes, len); - buf->length += len; -} - -static void sbprintf(sbuf *buf, const char *fmt, ...) { - char temp[GRPC_HTTPCLI_MAX_HEADER_LENGTH]; - size_t len; - va_list args; - - va_start(args, fmt); - len = vsprintf(temp, fmt, args); - va_end(args); - - sbuf_append(buf, temp, len); -} - -static void fill_common_header(const grpc_httpcli_request *request, sbuf *buf) { +static void fill_common_header(const grpc_httpcli_request *request, gpr_strvec *buf) { size_t i; - sbprintf(buf, "%s HTTP/1.0\r\n", request->path); + gpr_strvec_add(buf, gpr_strdup(request->path)); + gpr_strvec_add(buf, gpr_strdup(" HTTP/1.0\r\n")); /* just in case some crazy server really expects HTTP/1.1 */ - sbprintf(buf, "Host: %s\r\n", request->host); - sbprintf(buf, "Connection: close\r\n"); - sbprintf(buf, "User-Agent: %s\r\n", GRPC_HTTPCLI_USER_AGENT); + gpr_strvec_add(buf, gpr_strdup("Host: ")); + gpr_strvec_add(buf, gpr_strdup(request->host)); + gpr_strvec_add(buf, gpr_strdup("\r\n")); + gpr_strvec_add(buf, gpr_strdup("Connection: close\r\n")); + gpr_strvec_add(buf, gpr_strdup("User-Agent: "GRPC_HTTPCLI_USER_AGENT"\r\n")); /* user supplied headers */ for (i = 0; i < request->hdr_count; i++) { - sbprintf(buf, "%s: %s\r\n", request->hdrs[i].key, request->hdrs[i].value); + gpr_strvec_add(buf, gpr_strdup(request->hdrs[i].key)); + gpr_strvec_add(buf, gpr_strdup(": ")); + gpr_strvec_add(buf, gpr_strdup(request->hdrs[i].value)); + gpr_strvec_add(buf, gpr_strdup("\r\n")); } } gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request) { - sbuf out = {0, 0, NULL}; + gpr_strvec out; + char *flat; + size_t flat_len; - sbprintf(&out, "GET "); + gpr_strvec_init(&out); + gpr_strvec_add(&out, gpr_strdup("GET ")); fill_common_header(request, &out); - sbprintf(&out, "\r\n"); + gpr_strvec_add(&out, gpr_strdup("\r\n")); - return gpr_slice_new(out.data, out.length, gpr_free); + flat = gpr_strvec_flatten(&out, &flat_len); + gpr_strvec_destroy(&out); + + return gpr_slice_new(flat, flat_len, gpr_free); } gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request, const char *body_bytes, size_t body_size) { - sbuf out = {0, 0, NULL}; + gpr_strvec out; + char *tmp; + size_t out_len; size_t i; - sbprintf(&out, "POST "); + gpr_strvec_init(&out); + + gpr_strvec_add(&out, gpr_strdup("POST ")); fill_common_header(request, &out); if (body_bytes) { gpr_uint8 has_content_type = 0; @@ -108,14 +98,18 @@ gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request, } } if (!has_content_type) { - sbprintf(&out, "Content-Type: text/plain\r\n"); + gpr_strvec_add(&out, gpr_strdup("Content-Type: text/plain\r\n")); } - sbprintf(&out, "Content-Length: %lu\r\n", (unsigned long)body_size); + gpr_asprintf(&tmp, "Content-Length: %lu\r\n", (unsigned long)body_size); + gpr_strvec_add(&out, tmp); } - sbprintf(&out, "\r\n"); + gpr_strvec_add(&out, gpr_strdup("\r\n")); + tmp = gpr_strvec_flatten(&out, &out_len); if (body_bytes) { - sbuf_append(&out, body_bytes, body_size); + tmp = gpr_realloc(tmp, out_len + body_size); + memcpy(tmp + out_len, body_bytes, body_size); + out_len += body_size; } - return gpr_slice_new(out.data, out.length, gpr_free); + return gpr_slice_new(tmp, out_len, gpr_free); } -- cgit v1.2.3 From 96756e6f07177a226c214408fe6d4f1d8b0e07f2 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 14:43:50 -0800 Subject: Added comments --- src/core/support/string.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core/support/string.h b/src/core/support/string.h index d8fd2638ef..64e06d3b6a 100644 --- a/src/core/support/string.h +++ b/src/core/support/string.h @@ -86,16 +86,20 @@ int gpr_asprintf(char **strp, const char *format, ...); if it is non-null. */ char *gpr_strjoin(const char **strs, size_t nstrs, size_t *total_length); -/* A vector of strings... addition takes ownership of strings */ +/* A vector of strings... for building up a final string one piece at a time */ typedef struct { char **strs; size_t count; size_t capacity; } gpr_strvec; +/* Initialize/destroy */ void gpr_strvec_init(gpr_strvec *strs); void gpr_strvec_destroy(gpr_strvec *strs); +/* Add a string to a strvec, takes ownership of the string */ void gpr_strvec_add(gpr_strvec *strs, char *add); +/* Return a joined string with all added substrings, optionally setting + total_length as per gpr_strjoin */ char *gpr_strvec_flatten(gpr_strvec *strs, size_t *total_length); #ifdef __cplusplus -- cgit v1.2.3 From c92499d1d91091d4a2cd437f46534a353fb0bee6 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 23 Jan 2015 14:52:01 -0800 Subject: Removed some duplicate stream code --- src/node/client.js | 6 +-- src/node/server.js | 2 +- src/node/surface_client.js | 56 ++++++++++++--------------- src/node/surface_server.js | 73 +++++++++++++----------------------- src/node/test/interop_sanity_test.js | 2 +- 5 files changed, 56 insertions(+), 83 deletions(-) diff --git a/src/node/client.js b/src/node/client.js index 2fefd14bbc..7007852b93 100644 --- a/src/node/client.js +++ b/src/node/client.js @@ -105,7 +105,7 @@ function GrpcClientStream(call, serialize, deserialize) { return; } var data = event.data; - if (self.push(data) && data != null) { + if (self.push(self.deserialize(data)) && data != null) { self._call.startRead(readCallback); } else { reading = false; @@ -155,7 +155,7 @@ GrpcClientStream.prototype._read = function(size) { */ GrpcClientStream.prototype._write = function(chunk, encoding, callback) { var self = this; - self._call.startWrite(chunk, function(event) { + self._call.startWrite(self.serialize(chunk), function(event) { callback(); }, 0); }; @@ -185,7 +185,7 @@ function makeRequest(channel, if (metadata) { call.addMetadata(metadata); } - return new GrpcClientStream(call); + return new GrpcClientStream(call, serialize, deserialize); } /** diff --git a/src/node/server.js b/src/node/server.js index eca20aa5fd..fc7144a9c1 100644 --- a/src/node/server.js +++ b/src/node/server.js @@ -151,7 +151,7 @@ function GrpcServerStream(call, serialize, deserialize) { return; } var data = event.data; - if (self.push(deserialize(data)) && data != null) { + if (self.push(self.deserialize(data)) && data != null) { self._call.startRead(readCallback); } else { reading = false; diff --git a/src/node/surface_client.js b/src/node/surface_client.js index 996e3d101f..8996f0be40 100644 --- a/src/node/surface_client.js +++ b/src/node/surface_client.js @@ -63,18 +63,16 @@ util.inherits(ClientReadableObjectStream, Readable); * client side. Extends from stream.Readable. * @constructor * @param {stream} stream Underlying binary Duplex stream for the call - * @param {function(Buffer)} deserialize Function for deserializing binary data - * @param {object} options Stream options */ -function ClientReadableObjectStream(stream, deserialize, options) { - options = _.extend(options, {objectMode: true}); +function ClientReadableObjectStream(stream) { + var options = {objectMode: true}; Readable.call(this, options); this._stream = stream; var self = this; forwardEvent(stream, this, 'status'); forwardEvent(stream, this, 'metadata'); this._stream.on('data', function forwardData(chunk) { - if (!self.push(deserialize(chunk))) { + if (!self.push(chunk)) { self._stream.pause(); } }); @@ -88,14 +86,11 @@ util.inherits(ClientWritableObjectStream, Writable); * client side. Extends from stream.Writable. * @constructor * @param {stream} stream Underlying binary Duplex stream for the call - * @param {function(*):Buffer} serialize Function for serializing objects - * @param {object} options Stream options */ -function ClientWritableObjectStream(stream, serialize, options) { - options = _.extend(options, {objectMode: true}); +function ClientWritableObjectStream(stream) { + var options = {objectMode: true}; Writable.call(this, options); this._stream = stream; - this._serialize = serialize; forwardEvent(stream, this, 'status'); forwardEvent(stream, this, 'metadata'); this.on('finish', function() { @@ -111,20 +106,16 @@ util.inherits(ClientBidiObjectStream, Duplex); * client side. Extends from stream.Duplex. * @constructor * @param {stream} stream Underlying binary Duplex stream for the call - * @param {function(*):Buffer} serialize Function for serializing objects - * @param {function(Buffer)} deserialize Function for deserializing binary data - * @param {object} options Stream options */ -function ClientBidiObjectStream(stream, serialize, deserialize, options) { - options = _.extend(options, {objectMode: true}); +function ClientBidiObjectStream(stream) { + var options = {objectMode: true}; Duplex.call(this, options); this._stream = stream; - this._serialize = serialize; var self = this; forwardEvent(stream, this, 'status'); forwardEvent(stream, this, 'metadata'); this._stream.on('data', function forwardData(chunk) { - if (!self.push(deserialize(chunk))) { + if (!self.push(chunk)) { self._stream.pause(); } }); @@ -160,7 +151,7 @@ ClientBidiObjectStream.prototype._read = _read; * @param {function(Error)} callback Callback to call when finished writing */ function _write(chunk, encoding, callback) { - this._stream.write(this._serialize(chunk), encoding, callback); + this._stream.write(chunk, encoding, callback); } /** @@ -196,15 +187,16 @@ function makeUnaryRequestFunction(method, serialize, deserialize) { * @return {EventEmitter} An event emitter for stream related events */ function makeUnaryRequest(argument, callback, metadata, deadline) { - var stream = client.makeRequest(this.channel, method, metadata, deadline); + var stream = client.makeRequest(this.channel, method, serialize, + deserialize, metadata, deadline); var emitter = new EventEmitter(); forwardEvent(stream, emitter, 'status'); forwardEvent(stream, emitter, 'metadata'); - stream.write(serialize(argument)); + stream.write(argument); stream.end(); stream.on('data', function forwardData(chunk) { try { - callback(null, deserialize(chunk)); + callback(null, chunk); } catch (e) { callback(e); } @@ -236,11 +228,12 @@ function makeClientStreamRequestFunction(method, serialize, deserialize) { * @return {EventEmitter} An event emitter for stream related events */ function makeClientStreamRequest(callback, metadata, deadline) { - var stream = client.makeRequest(this.channel, method, metadata, deadline); - var obj_stream = new ClientWritableObjectStream(stream, serialize, {}); + var stream = client.makeRequest(this.channel, method, serialize, + deserialize, metadata, deadline); + var obj_stream = new ClientWritableObjectStream(stream); stream.on('data', function forwardData(chunk) { try { - callback(null, deserialize(chunk)); + callback(null, chunk); } catch (e) { callback(e); } @@ -272,9 +265,10 @@ function makeServerStreamRequestFunction(method, serialize, deserialize) { * @return {EventEmitter} An event emitter for stream related events */ function makeServerStreamRequest(argument, metadata, deadline) { - var stream = client.makeRequest(this.channel, method, metadata, deadline); - var obj_stream = new ClientReadableObjectStream(stream, deserialize, {}); - stream.write(serialize(argument)); + var stream = client.makeRequest(this.channel, method, serialize, + deserialize, metadata, deadline); + var obj_stream = new ClientReadableObjectStream(stream); + stream.write(argument); stream.end(); return obj_stream; } @@ -301,11 +295,9 @@ function makeBidiStreamRequestFunction(method, serialize, deserialize) { * @return {EventEmitter} An event emitter for stream related events */ function makeBidiStreamRequest(metadata, deadline) { - var stream = client.makeRequest(this.channel, method, metadata, deadline); - var obj_stream = new ClientBidiObjectStream(stream, - serialize, - deserialize, - {}); + var stream = client.makeRequest(this.channel, method, serialize, + deserialize, metadata, deadline); + var obj_stream = new ClientBidiObjectStream(stream); return obj_stream; } return makeBidiStreamRequest; diff --git a/src/node/surface_server.js b/src/node/surface_server.js index bc688839fe..28af5ab42f 100644 --- a/src/node/surface_server.js +++ b/src/node/surface_server.js @@ -54,11 +54,9 @@ util.inherits(ServerReadableObjectStream, Readable); * server side. Extends from stream.Readable. * @constructor * @param {stream} stream Underlying binary Duplex stream for the call - * @param {function(Buffer)} deserialize Function for deserializing binary data - * @param {object} options Stream options */ -function ServerReadableObjectStream(stream, deserialize, options) { - options = _.extend(options, {objectMode: true}); +function ServerReadableObjectStream(stream) { + var options = {objectMode: true}; Readable.call(this, options); this._stream = stream; Object.defineProperty(this, 'cancelled', { @@ -66,7 +64,7 @@ function ServerReadableObjectStream(stream, deserialize, options) { }); var self = this; this._stream.on('data', function forwardData(chunk) { - if (!self.push(deserialize(chunk))) { + if (!self.push(chunk)) { self._stream.pause(); } }); @@ -83,14 +81,11 @@ util.inherits(ServerWritableObjectStream, Writable); * server side. Extends from stream.Writable. * @constructor * @param {stream} stream Underlying binary Duplex stream for the call - * @param {function(*):Buffer} serialize Function for serializing objects - * @param {object} options Stream options */ -function ServerWritableObjectStream(stream, serialize, options) { - options = _.extend(options, {objectMode: true}); +function ServerWritableObjectStream(stream) { + var options = {objectMode: true}; Writable.call(this, options); this._stream = stream; - this._serialize = serialize; this.on('finish', function() { this._stream.end(); }); @@ -103,18 +98,14 @@ util.inherits(ServerBidiObjectStream, Duplex); * server side. Extends from stream.Duplex. * @constructor * @param {stream} stream Underlying binary Duplex stream for the call - * @param {function(*):Buffer} serialize Function for serializing objects - * @param {function(Buffer)} deserialize Function for deserializing binary data - * @param {object} options Stream options */ -function ServerBidiObjectStream(stream, serialize, deserialize, options) { - options = _.extend(options, {objectMode: true}); +function ServerBidiObjectStream(stream) { + var options = {objectMode: true}; Duplex.call(this, options); this._stream = stream; - this._serialize = serialize; var self = this; this._stream.on('data', function forwardData(chunk) { - if (!self.push(deserialize(chunk))) { + if (!self.push(chunk)) { self._stream.pause(); } }); @@ -153,7 +144,7 @@ ServerBidiObjectStream.prototype._read = _read; * @param {function(Error)} callback Callback to call when finished writing */ function _write(chunk, encoding, callback) { - this._stream.write(this._serialize(chunk), encoding, callback); + this._stream.write(chunk, encoding, callback); } /** @@ -168,11 +159,9 @@ ServerBidiObjectStream.prototype._write = _write; /** * Creates a binary stream handler function from a unary handler function * @param {function(Object, function(Error, *))} handler Unary call handler - * @param {function(*):Buffer} serialize Serialization function - * @param {function(Buffer):*} deserialize Deserialization function * @return {function(stream)} Binary stream handler */ -function makeUnaryHandler(handler, serialize, deserialize) { +function makeUnaryHandler(handler) { /** * Handles a stream by reading a single data value, passing it to the handler, * and writing the response back to the stream. @@ -180,7 +169,7 @@ function makeUnaryHandler(handler, serialize, deserialize) { */ return function handleUnaryCall(stream) { stream.on('data', function handleUnaryData(value) { - var call = {request: deserialize(value)}; + var call = {request: value}; Object.defineProperty(call, 'cancelled', { get: function() { return stream.cancelled;} }); @@ -188,7 +177,7 @@ function makeUnaryHandler(handler, serialize, deserialize) { if (err) { stream.emit('error', err); } else { - stream.write(serialize(value)); + stream.write(value); stream.end(); } }); @@ -201,23 +190,21 @@ function makeUnaryHandler(handler, serialize, deserialize) { * function * @param {function(Readable, function(Error, *))} handler Client stream call * handler - * @param {function(*):Buffer} serialize Serialization function - * @param {function(Buffer):*} deserialize Deserialization function * @return {function(stream)} Binary stream handler */ -function makeClientStreamHandler(handler, serialize, deserialize) { +function makeClientStreamHandler(handler) { /** * Handles a stream by passing a deserializing stream to the handler and * writing the response back to the stream. * @param {stream} stream Binary data stream */ return function handleClientStreamCall(stream) { - var object_stream = new ServerReadableObjectStream(stream, deserialize, {}); + var object_stream = new ServerReadableObjectStream(stream); handler(object_stream, function sendClientStreamData(err, value) { if (err) { stream.emit('error', err); } else { - stream.write(serialize(value)); + stream.write(value); stream.end(); } }); @@ -228,11 +215,9 @@ function makeClientStreamHandler(handler, serialize, deserialize) { * Creates a binary stream handler function from a server stream handler * function * @param {function(Writable)} handler Server stream call handler - * @param {function(*):Buffer} serialize Serialization function - * @param {function(Buffer):*} deserialize Deserialization function * @return {function(stream)} Binary stream handler */ -function makeServerStreamHandler(handler, serialize, deserialize) { +function makeServerStreamHandler(handler) { /** * Handles a stream by attaching it to a serializing stream, and passing it to * the handler. @@ -240,10 +225,8 @@ function makeServerStreamHandler(handler, serialize, deserialize) { */ return function handleServerStreamCall(stream) { stream.on('data', function handleClientData(value) { - var object_stream = new ServerWritableObjectStream(stream, - serialize, - {}); - object_stream.request = deserialize(value); + var object_stream = new ServerWritableObjectStream(stream); + object_stream.request = value; handler(object_stream); }); }; @@ -252,21 +235,16 @@ function makeServerStreamHandler(handler, serialize, deserialize) { /** * Creates a binary stream handler function from a bidi stream handler function * @param {function(Duplex)} handler Unary call handler - * @param {function(*):Buffer} serialize Serialization function - * @param {function(Buffer):*} deserialize Deserialization function * @return {function(stream)} Binary stream handler */ -function makeBidiStreamHandler(handler, serialize, deserialize) { +function makeBidiStreamHandler(handler) { /** * Handles a stream by wrapping it in a serializing and deserializing object * stream, and passing it to the handler. * @param {stream} stream Binary data stream */ return function handleBidiStreamCall(stream) { - var object_stream = new ServerBidiObjectStream(stream, - serialize, - deserialize, - {}); + var object_stream = new ServerBidiObjectStream(stream); handler(object_stream); }; } @@ -341,10 +319,13 @@ function makeServerConstructor(services) { common.fullyQualifiedName(method) + ' not provided.'); } var binary_handler = handler_makers[method_type]( - service_handlers[service_name][decapitalize(method.name)], - common.serializeCls(method.resolvedResponseType.build()), - common.deserializeCls(method.resolvedRequestType.build())); - server.register(prefix + capitalize(method.name), binary_handler); + service_handlers[service_name][decapitalize(method.name)]); + var serialize = common.serializeCls( + method.resolvedResponseType.build()); + var deserialize = common.deserializeCls( + method.resolvedRequestType.build()); + server.register(prefix + capitalize(method.name), binary_handler, + serialize, deserialize); }); }, this); } diff --git a/src/node/test/interop_sanity_test.js b/src/node/test/interop_sanity_test.js index 3c062b9788..8ea48c359f 100644 --- a/src/node/test/interop_sanity_test.js +++ b/src/node/test/interop_sanity_test.js @@ -65,7 +65,7 @@ describe('Interop tests', function() { it('should pass ping_pong', function(done) { interop_client.runTest(port, name_override, 'ping_pong', true, done); }); - it.skip('should pass empty_stream', function(done) { + it('should pass empty_stream', function(done) { interop_client.runTest(port, name_override, 'empty_stream', true, done); }); }); -- cgit v1.2.3 From efcb4da8e005a5c0f24a64f4943095fd4e60fdc0 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 14:57:02 -0800 Subject: Add missing free --- src/core/channel/connected_channel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c index 47c0ed3b88..55486ed5c3 100644 --- a/src/core/channel/connected_channel.c +++ b/src/core/channel/connected_channel.c @@ -450,6 +450,7 @@ static void recv_batch(void *user_data, grpc_transport *transport, (int)calld->incoming_message.length, (int)calld->incoming_message_length); recv_error(chand, calld, __LINE__, message); + gpr_free(message); } call_op.type = GRPC_RECV_HALF_CLOSE; call_op.dir = GRPC_CALL_UP; -- cgit v1.2.3 From 46c2461c8bfc60311f2eb607c35389f6437a02b1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 23 Jan 2015 15:00:38 -0800 Subject: Removed unnecessary bidi stream wrappers --- src/node/surface_client.js | 42 +++------------------------------------- src/node/surface_server.js | 48 ++-------------------------------------------- 2 files changed, 5 insertions(+), 85 deletions(-) diff --git a/src/node/surface_client.js b/src/node/surface_client.js index 8996f0be40..abec999cab 100644 --- a/src/node/surface_client.js +++ b/src/node/surface_client.js @@ -98,36 +98,9 @@ function ClientWritableObjectStream(stream) { }); } - -util.inherits(ClientBidiObjectStream, Duplex); - -/** - * Class for representing a gRPC bidi streaming call as a Node stream on the - * client side. Extends from stream.Duplex. - * @constructor - * @param {stream} stream Underlying binary Duplex stream for the call - */ -function ClientBidiObjectStream(stream) { - var options = {objectMode: true}; - Duplex.call(this, options); - this._stream = stream; - var self = this; - forwardEvent(stream, this, 'status'); - forwardEvent(stream, this, 'metadata'); - this._stream.on('data', function forwardData(chunk) { - if (!self.push(chunk)) { - self._stream.pause(); - } - }); - this._stream.pause(); - this.on('finish', function() { - this._stream.end(); - }); -} - /** * _read implementation for both types of streams that allow reading. - * @this {ClientReadableObjectStream|ClientBidiObjectStream} + * @this {ClientReadableObjectStream} * @param {number} size Ignored */ function _read(size) { @@ -138,14 +111,10 @@ function _read(size) { * See docs for _read */ ClientReadableObjectStream.prototype._read = _read; -/** - * See docs for _read - */ -ClientBidiObjectStream.prototype._read = _read; /** * _write implementation for both types of streams that allow writing - * @this {ClientWritableObjectStream|ClientBidiObjectStream} + * @this {ClientWritableObjectStream} * @param {*} chunk The value to write to the stream * @param {string} encoding Ignored * @param {function(Error)} callback Callback to call when finished writing @@ -158,10 +127,6 @@ function _write(chunk, encoding, callback) { * See docs for _write */ ClientWritableObjectStream.prototype._write = _write; -/** - * See docs for _write - */ -ClientBidiObjectStream.prototype._write = _write; /** * Get a function that can make unary requests to the specified method. @@ -297,8 +262,7 @@ function makeBidiStreamRequestFunction(method, serialize, deserialize) { function makeBidiStreamRequest(metadata, deadline) { var stream = client.makeRequest(this.channel, method, serialize, deserialize, metadata, deadline); - var obj_stream = new ClientBidiObjectStream(stream); - return obj_stream; + return stream; } return makeBidiStreamRequest; } diff --git a/src/node/surface_server.js b/src/node/surface_server.js index 28af5ab42f..e3c48b13e1 100644 --- a/src/node/surface_server.js +++ b/src/node/surface_server.js @@ -90,34 +90,6 @@ function ServerWritableObjectStream(stream) { this._stream.end(); }); } - -util.inherits(ServerBidiObjectStream, Duplex); - -/** - * Class for representing a gRPC bidi streaming call as a Node stream on the - * server side. Extends from stream.Duplex. - * @constructor - * @param {stream} stream Underlying binary Duplex stream for the call - */ -function ServerBidiObjectStream(stream) { - var options = {objectMode: true}; - Duplex.call(this, options); - this._stream = stream; - var self = this; - this._stream.on('data', function forwardData(chunk) { - if (!self.push(chunk)) { - self._stream.pause(); - } - }); - this._stream.on('end', function forwardEnd() { - self.push(null); - }); - this._stream.pause(); - this.on('finish', function() { - this._stream.end(); - }); -} - /** * _read implementation for both types of streams that allow reading. * @this {ServerReadableObjectStream|ServerBidiObjectStream} @@ -131,14 +103,10 @@ function _read(size) { * See docs for _read */ ServerReadableObjectStream.prototype._read = _read; -/** - * See docs for _read - */ -ServerBidiObjectStream.prototype._read = _read; /** * _write implementation for both types of streams that allow writing - * @this {ServerWritableObjectStream|ServerBidiObjectStream} + * @this {ServerWritableObjectStream} * @param {*} chunk The value to write to the stream * @param {string} encoding Ignored * @param {function(Error)} callback Callback to call when finished writing @@ -151,10 +119,6 @@ function _write(chunk, encoding, callback) { * See docs for _write */ ServerWritableObjectStream.prototype._write = _write; -/** - * See docs for _write - */ -ServerBidiObjectStream.prototype._write = _write; /** * Creates a binary stream handler function from a unary handler function @@ -238,15 +202,7 @@ function makeServerStreamHandler(handler) { * @return {function(stream)} Binary stream handler */ function makeBidiStreamHandler(handler) { - /** - * Handles a stream by wrapping it in a serializing and deserializing object - * stream, and passing it to the handler. - * @param {stream} stream Binary data stream - */ - return function handleBidiStreamCall(stream) { - var object_stream = new ServerBidiObjectStream(stream); - handler(object_stream); - }; + return handler; } /** -- cgit v1.2.3 From 37d4eb56f04de5516bffb6719865d206a84854f6 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 15:03:10 -0800 Subject: Remove use of sprintf --- test/core/channel/metadata_buffer_test.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/core/channel/metadata_buffer_test.c b/test/core/channel/metadata_buffer_test.c index aa2399272f..b34758345a 100644 --- a/test/core/channel/metadata_buffer_test.c +++ b/test/core/channel/metadata_buffer_test.c @@ -32,6 +32,7 @@ */ #include "src/core/channel/metadata_buffer.h" +#include "src/core/support/string.h" #include #include #include "test/core/util/test_config.h" @@ -45,9 +46,9 @@ static gpr_slice construct_buffer(size_t prefix_length, size_t index) { gpr_slice buffer = gpr_slice_malloc(prefix_length + 32); memset(GPR_SLICE_START_PTR(buffer), 'a', prefix_length); GPR_SLICE_SET_LENGTH( - buffer, prefix_length + - sprintf((char *)GPR_SLICE_START_PTR(buffer) + prefix_length, - "%d", (int)index)); + buffer, + prefix_length + + gpr_ltoa(index, (char *)GPR_SLICE_START_PTR(buffer) + prefix_length)); return buffer; } -- cgit v1.2.3 From cf7bd708cffc35000923d164310095e04db25bdb Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 15:04:53 -0800 Subject: Remove use of sprintf --- test/core/channel/metadata_buffer_test.c | 2 +- test/core/end2end/tests/census_simple_request.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/test/core/channel/metadata_buffer_test.c b/test/core/channel/metadata_buffer_test.c index b34758345a..d2bc30cc3c 100644 --- a/test/core/channel/metadata_buffer_test.c +++ b/test/core/channel/metadata_buffer_test.c @@ -43,7 +43,7 @@ /* construct a buffer with some prefix followed by an integer converted to a string */ static gpr_slice construct_buffer(size_t prefix_length, size_t index) { - gpr_slice buffer = gpr_slice_malloc(prefix_length + 32); + gpr_slice buffer = gpr_slice_malloc(prefix_length + GPR_LTOA_MIN_BUFSIZE); memset(GPR_SLICE_START_PTR(buffer), 'a', prefix_length); GPR_SLICE_SET_LENGTH( buffer, diff --git a/test/core/end2end/tests/census_simple_request.c b/test/core/end2end/tests/census_simple_request.c index 719f0fe662..86cef437be 100644 --- a/test/core/end2end/tests/census_simple_request.c +++ b/test/core/end2end/tests/census_simple_request.c @@ -37,6 +37,7 @@ #include #include +#include "src/core/support/string.h" #include #include #include @@ -145,7 +146,7 @@ static void test_body(grpc_end2end_test_fixture f) { static void test_invoke_request_with_census( grpc_end2end_test_config config, const char *name, void (*body)(grpc_end2end_test_fixture f)) { - char fullname[64]; + char *fullname; grpc_end2end_test_fixture f; grpc_arg client_arg, server_arg; grpc_channel_args client_args, server_args; @@ -163,11 +164,12 @@ static void test_invoke_request_with_census( server_args.num_args = 1; server_args.args = &server_arg; - sprintf(fullname, "%s/%s", __FUNCTION__, name); + gpr_asprintf(&fullname, "%s/%s", __FUNCTION__, name); f = begin_test(config, fullname, &client_args, &server_args); body(f); end_test(&f); config.tear_down_data(&f); + gpr_free(fullname); } void grpc_end2end_tests(grpc_end2end_test_config config) { -- cgit v1.2.3 From 2be952ce28e5797d1f157e2c52ba3f80df8232fc Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 15:05:30 -0800 Subject: Remove use of sprintf --- test/core/end2end/tests/simple_request.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/core/end2end/tests/simple_request.c b/test/core/end2end/tests/simple_request.c index 23fc201d84..4a4b55afee 100644 --- a/test/core/end2end/tests/simple_request.c +++ b/test/core/end2end/tests/simple_request.c @@ -198,15 +198,16 @@ static void simple_request_body2(grpc_end2end_test_fixture f) { static void test_invoke_simple_request( grpc_end2end_test_config config, const char *name, void (*body)(grpc_end2end_test_fixture f)) { - char fullname[64]; + char *fullname; grpc_end2end_test_fixture f; - sprintf(fullname, "%s/%s", __FUNCTION__, name); + gpr_asprintf(&fullname, "%s/%s", __FUNCTION__, name); f = begin_test(config, fullname, NULL, NULL); body(f); end_test(&f); config.tear_down_data(&f); + gpr_free(fullname); } static void test_invoke_10_simple_requests(grpc_end2end_test_config config) { -- cgit v1.2.3 From 82df7446ae964804fe1d3cb384fc819fdd7aa951 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 15:06:44 -0800 Subject: Remove use of sprintf --- test/core/security/credentials_test.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c index ec21e0d42f..1c83cc8059 100644 --- a/test/core/security/credentials_test.c +++ b/test/core/security/credentials_test.c @@ -498,10 +498,8 @@ static void validate_service_account_http_request( char *expected_body = NULL; GPR_ASSERT(body != NULL); GPR_ASSERT(body_size != 0); - expected_body = gpr_malloc(strlen(expected_service_account_http_body_prefix) + - strlen(test_signed_jwt) + 1); - sprintf(expected_body, "%s%s", expected_service_account_http_body_prefix, - test_signed_jwt); + gpr_asprintf(&expected_body, "%s%s", + expected_service_account_http_body_prefix, test_signed_jwt); GPR_ASSERT(strlen(expected_body) == body_size); GPR_ASSERT(!memcmp(expected_body, body, body_size)); gpr_free(expected_body); -- cgit v1.2.3 From 7da8ef14c11f0e71c3aba31fd7df73eed6079cb0 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 15:07:22 -0800 Subject: Add missing include --- test/core/end2end/tests/simple_request.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/core/end2end/tests/simple_request.c b/test/core/end2end/tests/simple_request.c index 4a4b55afee..f8894a8ba9 100644 --- a/test/core/end2end/tests/simple_request.c +++ b/test/core/end2end/tests/simple_request.c @@ -37,6 +37,7 @@ #include #include +#include "src/core/support/string.h" #include #include #include -- cgit v1.2.3 From ec46f5fbd20f729b0d54e186ba862e34c7178bc2 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 15:08:40 -0800 Subject: Remove use of *printf --- test/core/statistics/hash_table_test.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/core/statistics/hash_table_test.c b/test/core/statistics/hash_table_test.c index ebfc2a2a9a..f8df2574a4 100644 --- a/test/core/statistics/hash_table_test.c +++ b/test/core/statistics/hash_table_test.c @@ -38,6 +38,7 @@ #include "src/core/statistics/hash_table.h" #include "src/core/support/murmur_hash.h" +#include "src/core/support/string.h" #include #include #include @@ -187,15 +188,15 @@ static void test_insertion_and_deletion_with_high_collision_rate(void) { census_ht_option opt = {CENSUS_HT_POINTER, 13, &force_collision, &cmp_str_keys, NULL, NULL}; census_ht* ht = census_ht_create(&opt); - char key_str[1000][10]; + char key_str[1000][GPR_LTOA_MIN_BUFSIZE]; gpr_uint64 val = 0; int i = 0; for (i = 0; i < 1000; i++) { census_ht_key key; key.ptr = key_str[i]; - sprintf(key_str[i], "%d", i); + gpr_ltoa(i, key_str[i]); census_ht_insert(ht, key, (void*)(&val)); - printf("%d\n", i); + gpr_log(GPR_INFO, "%d\n", i); GPR_ASSERT(census_ht_get_size(ht) == (i + 1)); } for (i = 0; i < 1000; i++) { -- cgit v1.2.3 From 68cc1afda5b59811b3eda1e6df1c0961d9e7ca14 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 15:10:53 -0800 Subject: Remove uses of sprintf --- test/core/transport/chttp2/hpack_table_test.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/test/core/transport/chttp2/hpack_table_test.c b/test/core/transport/chttp2/hpack_table_test.c index 1576a30c1b..29d30e6bbd 100644 --- a/test/core/transport/chttp2/hpack_table_test.c +++ b/test/core/transport/chttp2/hpack_table_test.c @@ -36,6 +36,7 @@ #include #include +#include "src/core/support/string.h" #include #include #include "test/core/util/test_config.h" @@ -131,8 +132,8 @@ static void test_static_lookup(void) { static void test_many_additions(void) { grpc_chttp2_hptbl tbl; int i; - char key[32]; - char value[32]; + char *key; + char *value; grpc_mdctx *mdctx; LOG_TEST(); @@ -141,14 +142,18 @@ static void test_many_additions(void) { grpc_chttp2_hptbl_init(&tbl, mdctx); for (i = 0; i < 1000000; i++) { - sprintf(key, "K:%d", i); - sprintf(value, "VALUE:%d", i); + gpr_asprintf(&key, "K:%d", i); + gpr_asprintf(&value, "VALUE:%d", i); grpc_chttp2_hptbl_add(&tbl, grpc_mdelem_from_strings(mdctx, key, value)); assert_index(&tbl, 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY, key, value); + gpr_free(key); + gpr_free(value); if (i) { - sprintf(key, "K:%d", i - 1); - sprintf(value, "VALUE:%d", i - 1); + gpr_asprintf(&key, "K:%d", i - 1); + gpr_asprintf(&value, "VALUE:%d", i - 1); assert_index(&tbl, 2 + GRPC_CHTTP2_LAST_STATIC_ENTRY, key, value); + gpr_free(key); + gpr_free(value); } } @@ -226,7 +231,7 @@ static void test_find(void) { /* overflow the string buffer, check find still works */ for (i = 0; i < 10000; i++) { - sprintf(buffer, "%d", i); + gpr_ltoa(i, buffer); grpc_chttp2_hptbl_add(&tbl, grpc_mdelem_from_strings(mdctx, "test", buffer)); } -- cgit v1.2.3 From 9bb2632309310037d9d3af858f1537c4da593fde Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 15:12:08 -0800 Subject: Remove uses of sprintf --- test/core/transport/chttp2/hpack_table_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/core/transport/chttp2/hpack_table_test.c b/test/core/transport/chttp2/hpack_table_test.c index 29d30e6bbd..d155dee9dc 100644 --- a/test/core/transport/chttp2/hpack_table_test.c +++ b/test/core/transport/chttp2/hpack_table_test.c @@ -250,7 +250,7 @@ static void test_find(void) { for (i = 0; i < tbl.num_ents; i++) { int expect = 9999 - i; - sprintf(buffer, "%d", expect); + gpr_ltoa(expect, buffer); r = find_simple(&tbl, "test", buffer); GPR_ASSERT(r.index == i + 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY); -- cgit v1.2.3 From 2ed57b48588270d37846c35694b0d484e912ff4b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 23 Jan 2015 15:15:46 -0800 Subject: Moved some code around for clarity --- src/node/surface_client.js | 28 ++++++++++++++-------------- src/node/surface_server.js | 27 ++++++++++++++------------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/node/surface_client.js b/src/node/surface_client.js index abec999cab..aba8feeada 100644 --- a/src/node/surface_client.js +++ b/src/node/surface_client.js @@ -79,6 +79,20 @@ function ClientReadableObjectStream(stream) { this._stream.pause(); } +/** + * _read implementation for both types of streams that allow reading. + * @this {ClientReadableObjectStream} + * @param {number} size Ignored + */ +function _read(size) { + this._stream.resume(); +} + +/** + * See docs for _read + */ +ClientReadableObjectStream.prototype._read = _read; + util.inherits(ClientWritableObjectStream, Writable); /** @@ -98,20 +112,6 @@ function ClientWritableObjectStream(stream) { }); } -/** - * _read implementation for both types of streams that allow reading. - * @this {ClientReadableObjectStream} - * @param {number} size Ignored - */ -function _read(size) { - this._stream.resume(); -} - -/** - * See docs for _read - */ -ClientReadableObjectStream.prototype._read = _read; - /** * _write implementation for both types of streams that allow writing * @this {ClientWritableObjectStream} diff --git a/src/node/surface_server.js b/src/node/surface_server.js index e3c48b13e1..07c5339f62 100644 --- a/src/node/surface_server.js +++ b/src/node/surface_server.js @@ -74,6 +74,20 @@ function ServerReadableObjectStream(stream) { this._stream.pause(); } +/** + * _read implementation for both types of streams that allow reading. + * @this {ServerReadableObjectStream|ServerBidiObjectStream} + * @param {number} size Ignored + */ +function _read(size) { + this._stream.resume(); +} + +/** + * See docs for _read + */ +ServerReadableObjectStream.prototype._read = _read; + util.inherits(ServerWritableObjectStream, Writable); /** @@ -90,19 +104,6 @@ function ServerWritableObjectStream(stream) { this._stream.end(); }); } -/** - * _read implementation for both types of streams that allow reading. - * @this {ServerReadableObjectStream|ServerBidiObjectStream} - * @param {number} size Ignored - */ -function _read(size) { - this._stream.resume(); -} - -/** - * See docs for _read - */ -ServerReadableObjectStream.prototype._read = _read; /** * _write implementation for both types of streams that allow writing -- cgit v1.2.3 From 28214ea1b24a374335a2a36691cb5d14e1234938 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 15:17:07 -0800 Subject: Remove uses of sprintf --- test/core/transport/chttp2/stream_encoder_test.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/test/core/transport/chttp2/stream_encoder_test.c b/test/core/transport/chttp2/stream_encoder_test.c index eb0f688f58..5e8ec0a1af 100644 --- a/test/core/transport/chttp2/stream_encoder_test.c +++ b/test/core/transport/chttp2/stream_encoder_test.c @@ -186,7 +186,7 @@ static void encode_int_to_str(int i, char *p) { static void test_decode_table_overflow(void) { int i; char key[3], value[3]; - char expect[128]; + char *expect; for (i = 0; i < 114; i++) { if (i > 0) { @@ -197,18 +197,21 @@ static void test_decode_table_overflow(void) { encode_int_to_str(i + 1, value); if (i + 61 >= 127) { - sprintf(expect, "000009 0104 deadbeef ff%02x 40 02%02x%02x 02%02x%02x", - i + 61 - 127, key[0], key[1], value[0], value[1]); + gpr_asprintf(&expect, + "000009 0104 deadbeef ff%02x 40 02%02x%02x 02%02x%02x", + i + 61 - 127, key[0], key[1], value[0], value[1]); } else if (i > 0) { - sprintf(expect, "000008 0104 deadbeef %02x 40 02%02x%02x 02%02x%02x", - 0x80 + 61 + i, key[0], key[1], value[0], value[1]); + gpr_asprintf(&expect, + "000008 0104 deadbeef %02x 40 02%02x%02x 02%02x%02x", + 0x80 + 61 + i, key[0], key[1], value[0], value[1]); } else { - sprintf(expect, "000007 0104 deadbeef 40 02%02x%02x 02%02x%02x", key[0], - key[1], value[0], value[1]); + gpr_asprintf(&expect, "000007 0104 deadbeef 40 02%02x%02x 02%02x%02x", + key[0], key[1], value[0], value[1]); } add_sopb_header(key, value); verify_sopb(0, 0, 0, expect); + gpr_free(expect); } /* if the above passes, then we must have just knocked this pair out of the -- cgit v1.2.3 From 03f75259c5a5ead4c336d3c353f15b72af0cdafb Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 15:22:42 -0800 Subject: Remove uses of sprintf --- test/core/transport/chttp2/timeout_encoding_test.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/test/core/transport/chttp2/timeout_encoding_test.c b/test/core/transport/chttp2/timeout_encoding_test.c index ffa0070e34..0ad90dbcef 100644 --- a/test/core/transport/chttp2/timeout_encoding_test.c +++ b/test/core/transport/chttp2/timeout_encoding_test.c @@ -36,6 +36,8 @@ #include #include +#include "src/core/support/string.h" +#include #include #include #include "test/core/util/test_config.h" @@ -93,16 +95,23 @@ void decode_suite(char ext, gpr_timespec (*answer)(long x)) { 1234567, 12345678, 123456789, 98765432, 9876543, 987654, 98765, 9876, 987, 98, 9}; int i; - char input[32]; + char *input; for (i = 0; i < GPR_ARRAY_SIZE(test_vals); i++) { - sprintf(input, "%ld%c", test_vals[i], ext); + gpr_asprintf(&input, "%ld%c", test_vals[i], ext); assert_decodes_as(input, answer(test_vals[i])); - sprintf(input, " %ld%c", test_vals[i], ext); + gpr_free(input); + + gpr_asprintf(&input, " %ld%c", test_vals[i], ext); assert_decodes_as(input, answer(test_vals[i])); - sprintf(input, "%ld %c", test_vals[i], ext); + gpr_free(input); + + gpr_asprintf(&input, "%ld %c", test_vals[i], ext); assert_decodes_as(input, answer(test_vals[i])); - sprintf(input, "%ld %c ", test_vals[i], ext); + gpr_free(input); + + gpr_asprintf(&input, "%ld %c ", test_vals[i], ext); assert_decodes_as(input, answer(test_vals[i])); + gpr_free(input); } } -- cgit v1.2.3 From 8ddf31272d1bf20e3c37901d6dad94fc2bbdd6d6 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 15:25:40 -0800 Subject: Remove uses of sprintf --- test/core/transport/metadata_test.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/test/core/transport/metadata_test.c b/test/core/transport/metadata_test.c index 804096d0e1..b23db894be 100644 --- a/test/core/transport/metadata_test.c +++ b/test/core/transport/metadata_test.c @@ -35,6 +35,7 @@ #include +#include "src/core/support/string.h" #include "src/core/transport/chttp2/bin_encoder.h" #include #include @@ -99,7 +100,7 @@ static void test_create_metadata(void) { static void test_create_many_ephemeral_metadata(void) { grpc_mdctx *ctx; - char buffer[256]; + char buffer[GPR_LTOA_MIN_BUFSIZE]; long i; size_t mdtab_capacity_before; @@ -109,7 +110,7 @@ static void test_create_many_ephemeral_metadata(void) { mdtab_capacity_before = grpc_mdctx_get_mdtab_capacity_test_only(ctx); /* add, and immediately delete a bunch of different elements */ for (i = 0; i < MANY; i++) { - sprintf(buffer, "%ld", i); + gpr_ltoa(i, buffer); grpc_mdelem_unref(grpc_mdelem_from_strings(ctx, "a", buffer)); } /* capacity should not grow */ @@ -120,7 +121,7 @@ static void test_create_many_ephemeral_metadata(void) { static void test_create_many_persistant_metadata(void) { grpc_mdctx *ctx; - char buffer[256]; + char buffer[GPR_LTOA_MIN_BUFSIZE]; long i; grpc_mdelem **created = gpr_malloc(sizeof(grpc_mdelem *) * MANY); grpc_mdelem *md; @@ -130,12 +131,12 @@ static void test_create_many_persistant_metadata(void) { ctx = grpc_mdctx_create(); /* add phase */ for (i = 0; i < MANY; i++) { - sprintf(buffer, "%ld", i); + gpr_ltoa(i, buffer); created[i] = grpc_mdelem_from_strings(ctx, "a", buffer); } /* verify phase */ for (i = 0; i < MANY; i++) { - sprintf(buffer, "%ld", i); + gpr_ltoa(i, buffer); md = grpc_mdelem_from_strings(ctx, "a", buffer); GPR_ASSERT(md == created[i]); grpc_mdelem_unref(md); @@ -176,7 +177,7 @@ static void test_spin_creating_the_same_thing(void) { static void test_things_stick_around(void) { grpc_mdctx *ctx; int i, j; - char buffer[64]; + char *buffer; int nstrs = 10000; grpc_mdstr **strs = gpr_malloc(sizeof(grpc_mdstr *) * nstrs); int *shuf = gpr_malloc(sizeof(int) * nstrs); @@ -187,9 +188,10 @@ static void test_things_stick_around(void) { ctx = grpc_mdctx_create(); for (i = 0; i < nstrs; i++) { - sprintf(buffer, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%dx", i); + gpr_asprintf(&buffer, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%dx", i); strs[i] = grpc_mdstr_from_string(ctx, buffer); shuf[i] = i; + gpr_free(buffer); } for (i = 0; i < nstrs; i++) { @@ -208,10 +210,11 @@ static void test_things_stick_around(void) { for (i = 0; i < nstrs; i++) { grpc_mdstr_unref(strs[shuf[i]]); for (j = i + 1; j < nstrs; j++) { - sprintf(buffer, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%dx", shuf[j]); + gpr_asprintf(&buffer, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%dx", shuf[j]); test = grpc_mdstr_from_string(ctx, buffer); GPR_ASSERT(test == strs[shuf[j]]); grpc_mdstr_unref(test); + gpr_free(buffer); } } -- cgit v1.2.3 From 3385782a65a6d4672b8a1f66087c87f97e0ad6d0 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 15:39:40 -0800 Subject: Remove uses of sprintf --- test/core/end2end/cq_verifier.c | 108 +++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 58 deletions(-) diff --git a/test/core/end2end/cq_verifier.c b/test/core/end2end/cq_verifier.c index 49b131c236..9c61a98b60 100644 --- a/test/core/end2end/cq_verifier.c +++ b/test/core/end2end/cq_verifier.c @@ -231,100 +231,92 @@ static void verify_matches(expectation *e, grpc_event *ev) { } } -static char *metadata_expectation_string(metadata *md) { - size_t len; +static void metadata_expectation(gpr_strvec *buf, metadata *md) { size_t i; - char *out; - char *p; - - if (!md) return gpr_strdup("nil"); - - for (len = 0, i = 0; i < md->count; i++) { - len += strlen(md->keys[i]); - len += strlen(md->values[i]); - } - len += 3 + md->count; - - p = out = gpr_malloc(len); - *p++ = '{'; - for (i = 0; i < md->count; i++) { - if (i) *p++ = ','; - p += sprintf(p, "%s:%s", md->keys[i], md->values[i]); + char *tmp; + + if (!md) { + gpr_strvec_add(buf, gpr_strdup("nil")); + } else { + for (i = 0; i < md->count; i++) { + gpr_asprintf(&tmp, "%c%s:%s", i ? ',' : '{', md->keys[i], md->values[i]); + gpr_strvec_add(buf, tmp); + } + gpr_strvec_add(buf, gpr_strdup("}")); } - *p++ = '}'; - *p++ = 0; - return out; } -static size_t expectation_to_string(char *out, expectation *e) { +static void expectation_to_strvec(gpr_strvec *buf, expectation *e) { gpr_timespec timeout; - char *str = NULL; - size_t len; + char *tmp; switch (e->type) { case GRPC_FINISH_ACCEPTED: - return sprintf(out, "GRPC_FINISH_ACCEPTED result=%d", + gpr_asprintf(&tmp, "GRPC_FINISH_ACCEPTED result=%d", e->data.finish_accepted); + gpr_strvec_add(buf, tmp); + break; case GRPC_WRITE_ACCEPTED: - return sprintf(out, "GRPC_WRITE_ACCEPTED result=%d", + gpr_asprintf(&tmp, "GRPC_WRITE_ACCEPTED result=%d", e->data.write_accepted); + gpr_strvec_add(buf, tmp); + break; case GRPC_INVOKE_ACCEPTED: - return sprintf(out, "GRPC_INVOKE_ACCEPTED"); + gpr_strvec_add(buf, gpr_strdup("GRPC_INVOKE_ACCEPTED")); + break; case GRPC_SERVER_RPC_NEW: timeout = gpr_time_sub(e->data.server_rpc_new.deadline, gpr_now()); - return sprintf(out, "GRPC_SERVER_RPC_NEW method=%s host=%s timeout=%fsec", + gpr_asprintf(&tmp, "GRPC_SERVER_RPC_NEW method=%s host=%s timeout=%fsec", e->data.server_rpc_new.method, e->data.server_rpc_new.host, timeout.tv_sec + 1e-9 * timeout.tv_nsec); + gpr_strvec_add(buf, tmp); + break; case GRPC_CLIENT_METADATA_READ: - str = metadata_expectation_string(e->data.client_metadata_read); - len = sprintf(out, "GRPC_CLIENT_METADATA_READ %s", str); - gpr_free(str); - return len; + gpr_strvec_add(buf, gpr_strdup("GRPC_CLIENT_METADATA_READ ")); + metadata_expectation(buf, e->data.client_metadata_read); + break; case GRPC_FINISHED: - str = metadata_expectation_string(e->data.finished.metadata); - len = sprintf(out, "GRPC_FINISHED status=%d details=%s %s", - e->data.finished.status, e->data.finished.details, str); - gpr_free(str); - return len; + gpr_asprintf(&tmp, "GRPC_FINISHED status=%d details=%s ", + e->data.finished.status, e->data.finished.details); + gpr_strvec_add(buf, tmp); + metadata_expectation(buf, e->data.finished.metadata); + break; case GRPC_READ: - if (e->data.read) { - str = - gpr_hexdump((char *)GPR_SLICE_START_PTR(*e->data.read), - GPR_SLICE_LENGTH(*e->data.read), GPR_HEXDUMP_PLAINTEXT); - } - len = sprintf(out, "GRPC_READ data=%s", str); - gpr_free(str); - return len; + gpr_strvec_add(buf, gpr_strdup("GRPC_READ data=")); + gpr_strvec_add(buf, gpr_hexdump((char *)GPR_SLICE_START_PTR(*e->data.read), + GPR_SLICE_LENGTH(*e->data.read), GPR_HEXDUMP_PLAINTEXT)); + break; case GRPC_SERVER_SHUTDOWN: - return sprintf(out, "GRPC_SERVER_SHUTDOWN"); + gpr_strvec_add(buf, gpr_strdup("GRPC_SERVER_SHUTDOWN")); + break; case GRPC_COMPLETION_DO_NOT_USE: case GRPC_QUEUE_SHUTDOWN: gpr_log(GPR_ERROR, "not implemented"); abort(); break; } - return 0; } -static char *expectations_to_string(cq_verifier *v) { +static void expectations_to_strvec(gpr_strvec *buf, cq_verifier *v) { /* allocate a large buffer: we're about to crash anyway */ - char *buffer = gpr_malloc(32 * 1024 * 1024); - char *p = buffer; expectation *e; for (e = v->expect.next; e != &v->expect; e = e->next) { - p += expectation_to_string(p, e); - *p++ = '\n'; + expectation_to_strvec(buf, e); + gpr_strvec_add(buf, gpr_strdup("\n")); } - - *p = 0; - return buffer; } static void fail_no_event_received(cq_verifier *v) { - char *expectations = expectations_to_string(v); - gpr_log(GPR_ERROR, "no event received, but expected:\n%s", expectations); - gpr_free(expectations); + gpr_strvec buf; + char *msg; + gpr_strvec_init(&buf); + gpr_strvec_add(&buf, gpr_strdup("no event received, but expected:\n")); + expectations_to_strvec(&buf, v); + msg = gpr_strvec_flatten(&buf, NULL); + gpr_log(GPR_ERROR, "%s", msg); + gpr_strvec_destroy(&buf); + gpr_free(msg); abort(); } -- cgit v1.2.3 From 715342eb192c885aba110738c0edee4242bafe5d Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 15:42:33 -0800 Subject: Remove uses of sprintf --- test/core/end2end/cq_verifier.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/test/core/end2end/cq_verifier.c b/test/core/end2end/cq_verifier.c index 9c61a98b60..7abe01abf2 100644 --- a/test/core/end2end/cq_verifier.c +++ b/test/core/end2end/cq_verifier.c @@ -325,9 +325,10 @@ void cq_verify(cq_verifier *v) { gpr_time_add(gpr_now(), gpr_time_from_micros(10 * GPR_US_PER_SEC)); grpc_event *ev; expectation *e; + char *s; + gpr_strvec have_tags; - char have_tags[512] = {0}; - char *phave = have_tags; + gpr_strvec_init(&have_tags); while (v->expect.next != &v->expect) { ev = grpc_completion_queue_next(v->cq, deadline); @@ -336,7 +337,8 @@ void cq_verify(cq_verifier *v) { } for (e = v->expect.next; e != &v->expect; e = e->next) { - phave += sprintf(phave, " %p", e->tag); + gpr_asprintf(&s, " %p", e->tag); + gpr_strvec_add(&have_tags, s); if (e->tag == ev->tag) { verify_matches(e, ev); e->next->prev = e->prev; @@ -346,15 +348,20 @@ void cq_verify(cq_verifier *v) { } } if (e == &v->expect) { - char *s = grpc_event_string(ev); + s = grpc_event_string(ev); gpr_log(GPR_ERROR, "event not found: %s", s); - gpr_log(GPR_ERROR, "have tags:%s", have_tags); gpr_free(s); + s = gpr_strvec_flatten(&have_tags, NULL); + gpr_log(GPR_ERROR, "have tags:%s", s); + gpr_free(s); + gpr_strvec_destroy(&have_tags); abort(); } grpc_event_finish(ev); } + + gpr_strvec_destroy(&have_tags); } void cq_verify_empty(cq_verifier *v) { -- cgit v1.2.3 From 3e33a50149ca1d89259737573c5d360000ac7bf3 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 22:35:06 -0800 Subject: Use a simpler growth algorithm --- src/core/support/string.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/support/string.c b/src/core/support/string.c index 008b2aac89..97bce60f94 100644 --- a/src/core/support/string.c +++ b/src/core/support/string.c @@ -14,7 +14,7 @@ * 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 + * 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 @@ -189,7 +189,7 @@ void gpr_strvec_destroy(gpr_strvec *sv) { void gpr_strvec_add(gpr_strvec *sv, char *str) { if (sv->count == sv->capacity) { - sv->capacity = GPR_MAX(sv->capacity + 8, sv->capacity * 3 / 2); + sv->capacity = GPR_MAX(sv->capacity + 8, sv->capacity * 2); sv->strs = gpr_realloc(sv->strs, sizeof(char*) * sv->capacity); } sv->strs[sv->count++] = str; -- cgit v1.2.3 From da8774cee2b6be0b2c31e5758bc94ad8a5665ef9 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 23 Jan 2015 22:41:34 -0800 Subject: remove stale comment --- test/core/end2end/cq_verifier.c | 1 - 1 file changed, 1 deletion(-) diff --git a/test/core/end2end/cq_verifier.c b/test/core/end2end/cq_verifier.c index 7abe01abf2..287f83eebc 100644 --- a/test/core/end2end/cq_verifier.c +++ b/test/core/end2end/cq_verifier.c @@ -298,7 +298,6 @@ static void expectation_to_strvec(gpr_strvec *buf, expectation *e) { } static void expectations_to_strvec(gpr_strvec *buf, cq_verifier *v) { - /* allocate a large buffer: we're about to crash anyway */ expectation *e; for (e = v->expect.next; e != &v->expect; e = e->next) { -- cgit v1.2.3 From 4097c1d2010ef378b8bdea65a5e7e4fd6788a698 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 26 Jan 2015 09:21:22 -0800 Subject: Shortened a function --- src/node/surface_client.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/node/surface_client.js b/src/node/surface_client.js index aba8feeada..b63ae13e8d 100644 --- a/src/node/surface_client.js +++ b/src/node/surface_client.js @@ -260,9 +260,8 @@ function makeBidiStreamRequestFunction(method, serialize, deserialize) { * @return {EventEmitter} An event emitter for stream related events */ function makeBidiStreamRequest(metadata, deadline) { - var stream = client.makeRequest(this.channel, method, serialize, - deserialize, metadata, deadline); - return stream; + return client.makeRequest(this.channel, method, serialize, + deserialize, metadata, deadline); } return makeBidiStreamRequest; } -- cgit v1.2.3 From 7eb6bb99d29c373994759494698a1a3f41fc5b46 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 26 Jan 2015 10:13:03 -0800 Subject: Removed all instances of == in js files --- src/node/examples/math_server.js | 7 ++++--- src/node/interop/interop_client.js | 2 +- src/node/server.js | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/node/examples/math_server.js b/src/node/examples/math_server.js index d649b4fd6d..e65cfe3002 100644 --- a/src/node/examples/math_server.js +++ b/src/node/examples/math_server.js @@ -52,7 +52,8 @@ var Server = grpc.buildServer([math.Math.service]); */ function mathDiv(call, cb) { var req = call.request; - if (req.divisor == 0) { + // Unary + is explicit coersion to integer + if (+req.divisor === 0) { cb(new Error('cannot divide by zero')); } cb(null, { @@ -89,7 +90,7 @@ function mathSum(call, cb) { // Here, call is a standard readable Node object Stream var sum = 0; call.on('data', function(data) { - sum += data.num | 0; + sum += (+data.num); }); call.on('end', function() { cb(null, {num: sum}); @@ -104,7 +105,7 @@ function mathDivMany(stream) { Transform.call(this, options); } DivTransform.prototype._transform = function(div_args, encoding, callback) { - if (div_args.divisor == 0) { + if (+div_args.divisor === 0) { callback(new Error('cannot divide by zero')); } callback(null, { diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js index cf75b9a77a..9306317b68 100644 --- a/src/node/interop/interop_client.js +++ b/src/node/interop/interop_client.js @@ -183,7 +183,7 @@ function pingPong(client, done) { assert.equal(response.payload.body.limit - response.payload.body.offset, response_sizes[index]); index += 1; - if (index == 4) { + if (index === 4) { call.end(); } else { call.write({ diff --git a/src/node/server.js b/src/node/server.js index fc7144a9c1..fe50acb5a1 100644 --- a/src/node/server.js +++ b/src/node/server.js @@ -233,7 +233,7 @@ function Server(options) { function handleNewCall(event) { var call = event.call; var data = event.data; - if (data == null) { + if (data === null) { return; } server.requestCall(handleNewCall); -- cgit v1.2.3 From 2c8d5165a6ed9f55818af5f7e9e07d7851fc030d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 26 Jan 2015 10:41:21 -0800 Subject: Added node test runner --- tools/run_tests/run_node.sh | 10 ++++++++++ tools/run_tests/run_tests.py | 18 ++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 tools/run_tests/run_node.sh diff --git a/tools/run_tests/run_node.sh b/tools/run_tests/run_node.sh new file mode 100644 index 0000000000..76f8a1a4f4 --- /dev/null +++ b/tools/run_tests/run_node.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -ex + +# change to grpc repo root +cd $(dirname $0)/../.. + +root=`pwd` + +$root/src/node/node_modules/mocha/bin/mocha $root/node/test diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index da849f04cb..141f1117ab 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -46,8 +46,8 @@ class CLanguage(object): self.make_target = make_target with open('tools/run_tests/tests.json') as f: js = json.load(f) - self.binaries = [tgt['name'] - for tgt in js + self.binaries = [tgt['name'] + for tgt in js if tgt['language'] == test_lang] def test_binaries(self, config): @@ -59,6 +59,19 @@ class CLanguage(object): def build_steps(self): return [] +class NodeLanguage(object): + + def __init__(self): + self.allow_hashing = False + + def test_binaries(self, config): + return ['tools/run_tests/run_node.sh'] + + def make_targets(self): + return [] + + def build_steps(self): + return [['tools/run_tests/build_node.sh']] class PhpLanguage(object): @@ -107,6 +120,7 @@ _DEFAULT = ['dbg', 'opt'] _LANGUAGES = { 'c++': CLanguage('cxx', 'c++'), 'c': CLanguage('c', 'c'), + 'node': NodeLanguage(), 'php': PhpLanguage(), 'python': PythonLanguage(), } -- cgit v1.2.3 From 51cab624b8fda39ad1a5709d817f5d82f0edbcd5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 26 Jan 2015 10:45:49 -0800 Subject: Added missing server shutdown to interop test runner --- src/node/test/interop_sanity_test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/node/test/interop_sanity_test.js b/src/node/test/interop_sanity_test.js index 8ea48c359f..6cc7d444cd 100644 --- a/src/node/test/interop_sanity_test.js +++ b/src/node/test/interop_sanity_test.js @@ -48,6 +48,9 @@ describe('Interop tests', function() { port = 'localhost:' + server_obj.port; done(); }); + after(function() { + server.shutdown(); + }); // This depends on not using a binary stream it('should pass empty_unary', function(done) { interop_client.runTest(port, name_override, 'empty_unary', true, done); -- cgit v1.2.3 From 6ed6036e02c42be3991b971d4018693954bcc281 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Wed, 21 Jan 2015 18:17:25 -0800 Subject: Updates the Java Dockerfiles to pull source from GitHub --- tools/dockerfile/grpc_java/Dockerfile | 3 --- tools/dockerfile/grpc_java_base/Dockerfile | 14 ++++++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/tools/dockerfile/grpc_java/Dockerfile b/tools/dockerfile/grpc_java/Dockerfile index 78659dedeb..c51ee1f214 100644 --- a/tools/dockerfile/grpc_java/Dockerfile +++ b/tools/dockerfile/grpc_java/Dockerfile @@ -1,9 +1,6 @@ # Dockerfile for the gRPC Java dev image FROM grpc/java_base -# Start the daemon that allows access to private git-on-borg repos -RUN /var/local/git/gcompute-tools/git-cookie-authdaemon - RUN cd /var/local/git/grpc-java/lib/okhttp && \ mvn -pl okhttp -am install RUN cd /var/local/git/grpc-java/lib/netty && \ diff --git a/tools/dockerfile/grpc_java_base/Dockerfile b/tools/dockerfile/grpc_java_base/Dockerfile index 44fa52c0e8..40be7b1c5b 100644 --- a/tools/dockerfile/grpc_java_base/Dockerfile +++ b/tools/dockerfile/grpc_java_base/Dockerfile @@ -20,14 +20,20 @@ ENV M2_HOME /var/local/apache-maven-3.2.1 ENV PATH $PATH:$JAVA_HOME/bin:$M2_HOME/bin ENV LD_LIBRARY_PATH /usr/local/lib -# Start the daemon that allows access to the protected git-on-borg repos -RUN /var/local/git/gcompute-tools/git-cookie-authdaemon +# Install a GitHub SSH service credential that gives access to the GitHub repo while it's private +# TODO: remove this once the repo is public +ADD .ssh .ssh +RUN chmod 600 .ssh/github.rsa +RUN mkdir -p $HOME/.ssh && echo 'Host github.com' > $HOME/.ssh/config +RUN echo " IdentityFile /.ssh/github.rsa" >> $HOME/.ssh/config +RUN echo 'StrictHostKeyChecking no' >> $HOME/.ssh/config -RUN git clone --recursive https://team.googlesource.com/one-platform-grpc-team/grpc-java /var/local/git/grpc-java +# Get the source from GitHub +RUN git clone --recursive git@github.com:google/grpc-java.git /var/local/git/grpc-java RUN cd /var/local/git/grpc-java/lib/okhttp && \ mvn -pl okhttp -am validate RUN cd /var/local/git/grpc-java/lib/netty && \ mvn -pl codec-http2 -am validate RUN cd /var/local/git/grpc-java && \ - mvn validate \ No newline at end of file + mvn validate -- cgit v1.2.3 From 7d5b1027edccdf9680a8b7c86a587e929ecae2c9 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Thu, 22 Jan 2015 12:09:50 -0800 Subject: Updates java_base to pull in protobuf --- tools/dockerfile/grpc_java_base/Dockerfile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/dockerfile/grpc_java_base/Dockerfile b/tools/dockerfile/grpc_java_base/Dockerfile index 40be7b1c5b..91ee218b47 100644 --- a/tools/dockerfile/grpc_java_base/Dockerfile +++ b/tools/dockerfile/grpc_java_base/Dockerfile @@ -28,6 +28,13 @@ RUN mkdir -p $HOME/.ssh && echo 'Host github.com' > $HOME/.ssh/config RUN echo " IdentityFile /.ssh/github.rsa" >> $HOME/.ssh/config RUN echo 'StrictHostKeyChecking no' >> $HOME/.ssh/config +# Get the protobuf source from GitHub and install it +RUN git clone --recursive git@github.com:google/protobuf.git /var/local/git/protobuf +RUN cd /var/local/git/protobuf && \ + ./autogen.sh && \ + ./configure --prefix=/usr && \ + make -j12 && make check && make install && make clean + # Get the source from GitHub RUN git clone --recursive git@github.com:google/grpc-java.git /var/local/git/grpc-java -- cgit v1.2.3 From 564b944b3cd06e4c19b9b72a7db322801cd4d107 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 26 Jan 2015 11:07:59 -0800 Subject: Started fixing php test runner --- tools/run_tests/build_php.sh | 8 +++----- tools/run_tests/run_tests.py | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tools/run_tests/build_php.sh b/tools/run_tests/build_php.sh index 6841656bdb..0a8d0c7492 100755 --- a/tools/run_tests/build_php.sh +++ b/tools/run_tests/build_php.sh @@ -2,14 +2,13 @@ set -ex +CONFIG=${CONFIG:-opt} + # change to grpc repo root cd $(dirname $0)/../.. root=`pwd` -export GRPC_LIB_SUBDIR=libs/opt - -# make the libraries -make -j static_c +export GRPC_LIB_SUBDIR=libs/$CONFIG # build php cd src/php @@ -18,4 +17,3 @@ cd ext/grpc phpize ./configure --enable-grpc=$root make - diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index 141f1117ab..bfe6d7949b 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -82,7 +82,7 @@ class PhpLanguage(object): return ['src/php/bin/run_tests.sh'] def make_targets(self): - return [] + return ['static_c'] def build_steps(self): return [['tools/run_tests/build_php.sh']] -- cgit v1.2.3 From 41b6d9aad3a22edfdc7a17b3ed0be2483b93ba67 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Sun, 25 Jan 2015 16:25:03 -0800 Subject: Switched to using protobuf-2.6.1 for now --- tools/dockerfile/grpc_java_base/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/dockerfile/grpc_java_base/Dockerfile b/tools/dockerfile/grpc_java_base/Dockerfile index 91ee218b47..15c7b31816 100644 --- a/tools/dockerfile/grpc_java_base/Dockerfile +++ b/tools/dockerfile/grpc_java_base/Dockerfile @@ -29,7 +29,7 @@ RUN echo " IdentityFile /.ssh/github.rsa" >> $HOME/.ssh/config RUN echo 'StrictHostKeyChecking no' >> $HOME/.ssh/config # Get the protobuf source from GitHub and install it -RUN git clone --recursive git@github.com:google/protobuf.git /var/local/git/protobuf +RUN git clone --recursive --branch v2.6.1 git@github.com:google/protobuf.git /var/local/git/protobuf RUN cd /var/local/git/protobuf && \ ./autogen.sh && \ ./configure --prefix=/usr && \ -- cgit v1.2.3 From 12e12a39ab27a19560377d177041065366f2cdd3 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Wed, 21 Jan 2015 18:17:25 -0800 Subject: Updates the Java Dockerfiles to pull source from GitHub --- tools/dockerfile/grpc_java_base/Dockerfile | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/dockerfile/grpc_java_base/Dockerfile b/tools/dockerfile/grpc_java_base/Dockerfile index 15c7b31816..3271d1b2c2 100644 --- a/tools/dockerfile/grpc_java_base/Dockerfile +++ b/tools/dockerfile/grpc_java_base/Dockerfile @@ -35,9 +35,6 @@ RUN cd /var/local/git/protobuf && \ ./configure --prefix=/usr && \ make -j12 && make check && make install && make clean -# Get the source from GitHub -RUN git clone --recursive git@github.com:google/grpc-java.git /var/local/git/grpc-java - RUN cd /var/local/git/grpc-java/lib/okhttp && \ mvn -pl okhttp -am validate RUN cd /var/local/git/grpc-java/lib/netty && \ -- cgit v1.2.3 From 3ff195d885dfb155b5d3112cc30a79a462077b33 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 10:29:46 -0800 Subject: Updates the java dockerfile and client command to reflect recent flag changes --- tools/dockerfile/grpc_java/Dockerfile | 2 +- tools/gce_setup/grpc_docker.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/dockerfile/grpc_java/Dockerfile b/tools/dockerfile/grpc_java/Dockerfile index c51ee1f214..f234f514e6 100644 --- a/tools/dockerfile/grpc_java/Dockerfile +++ b/tools/dockerfile/grpc_java/Dockerfile @@ -10,4 +10,4 @@ RUN cd /var/local/git/grpc-java && \ mvn install # Specify the default command such that the interop server runs on its known testing port -CMD ["/var/local/git/grpc-java/run-test-server.sh", "--transport=HTTP2_NETTY_TLS", "--grpc_version=2", "--port=8030"] +CMD ["/var/local/git/grpc-java/run-test-server.sh", "--use_tls=true", "--port=8030"] diff --git a/tools/gce_setup/grpc_docker.sh b/tools/gce_setup/grpc_docker.sh index 145685305c..d97f829435 100755 --- a/tools/gce_setup/grpc_docker.sh +++ b/tools/gce_setup/grpc_docker.sh @@ -655,7 +655,7 @@ grpc_interop_gen_go_cmd() { grpc_interop_gen_java_cmd() { local cmd_prefix="sudo docker run grpc/java"; local test_script="/var/local/git/grpc-java/run-test-client.sh"; - local test_script+=" --transport=NETTY_TLS --grpc_version=2" + local test_script+=" --server_host_override=foo.test.google.com --use_test_ca=true --use_tls=true" local the_cmd="$cmd_prefix $test_script $@"; echo $the_cmd } @@ -683,7 +683,7 @@ grpc_interop_gen_php_cmd() { # flags= .... # generic flags to include the command # cmd=$($grpc_gen_test_cmd $flags) grpc_interop_gen_cxx_cmd() { - local cmd_prefix="sudo docker run grpc/cxx"; + local cmd_prefix="sudo docker run grpc/cxx"; local test_script="/var/local/git/grpc/bins/opt/interop_client --enable_ssl"; local the_cmd="$cmd_prefix $test_script $@"; echo $the_cmd -- cgit v1.2.3 From 74b3232d395cd1b9fe23bc56f83d726932d57606 Mon Sep 17 00:00:00 2001 From: Chen Wang Date: Mon, 26 Jan 2015 11:23:16 -0800 Subject: 1) Add protection header macro 2) remove some falgs with default values --- examples/tips/client.h | 5 +++++ examples/tips/client_main.cc | 17 ++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/examples/tips/client.h b/examples/tips/client.h index 3f4f1fd836..6ae9d50658 100644 --- a/examples/tips/client.h +++ b/examples/tips/client.h @@ -31,6 +31,9 @@ * */ +#ifndef __GRPCPP_EXAMPLES_TIPS_CLIENT_H_ +#define __GRPCPP_EXAMPLES_TIPS_CLIENT_H_ + #include #include @@ -52,3 +55,5 @@ class Client { } // namespace tips } // namespace examples } // namespace grpc + +#endif // __GRPCPP_EXAMPLES_TIPS_CLIENT_H_ diff --git a/examples/tips/client_main.cc b/examples/tips/client_main.cc index 17567b6f17..f4a3b09601 100644 --- a/examples/tips/client_main.cc +++ b/examples/tips/client_main.cc @@ -41,30 +41,29 @@ #include "examples/tips/client.h" #include "test/cpp/util/create_test_channel.h" -DEFINE_bool(enable_ssl, true, "Whether to use ssl/tls."); -DEFINE_bool(use_prod_roots, true, "True to use SSL roots for production GFE"); -DEFINE_int32(server_port, 0, "Server port."); -DEFINE_string(server_host, "127.0.0.1", "Server host to connect to"); -DEFINE_string(server_host_override, "foo.test.google.com", - "Override the server host which is sent in HTTP header"); +DEFINE_int32(server_port, 443, "Server port."); +DEFINE_string(server_host, + "pubsub-staging.googleapis.com", "Server host to connect to"); int main(int argc, char** argv) { grpc_init(); google::ParseCommandLineFlags(&argc, &argv, true); gpr_log(GPR_INFO, "Start TIPS client"); - GPR_ASSERT(FLAGS_server_port); const int host_port_buf_size = 1024; char host_port[host_port_buf_size]; snprintf(host_port, host_port_buf_size, "%s:%d", FLAGS_server_host.c_str(), FLAGS_server_port); std::shared_ptr channel( - grpc::CreateTestChannel(host_port, FLAGS_server_host_override, - FLAGS_enable_ssl, FLAGS_use_prod_roots)); + grpc::CreateTestChannel(host_port, + FLAGS_server_host, + true, // enable SSL + true)); // use prod roots grpc::examples::tips::Client client(channel); grpc::Status s = client.CreateTopic("test"); + gpr_log(GPR_INFO, "return code %d", s.code()); GPR_ASSERT(s.IsOk()); channel.reset(); -- cgit v1.2.3 From c279165f726dedc976fa9a73f1afe700639c6f3e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 26 Jan 2015 11:33:39 -0800 Subject: Got run_tests.py and node tests working --- tools/run_tests/build_node.sh | 7 +++---- tools/run_tests/run_node.sh | 2 +- tools/run_tests/run_tests.py | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) mode change 100644 => 100755 tools/run_tests/run_node.sh diff --git a/tools/run_tests/build_node.sh b/tools/run_tests/build_node.sh index 600b1bde8c..4b092982b2 100755 --- a/tools/run_tests/build_node.sh +++ b/tools/run_tests/build_node.sh @@ -2,19 +2,18 @@ set -ex +CONFIG=${CONFIG:-opt} + # change to grpc repo root cd $(dirname $0)/../.. # tells npm install to look for files in that directory export GRPC_ROOT=`pwd` # tells npm install the subdirectory with library files -export GRPC_LIB_SUBDIR=libs/opt +export GRPC_LIB_SUBDIR=libs/$CONFIG # tells npm install not to use default locations export GRPC_NO_INSTALL=yes -# build the c libraries -make -j static_c - cd src/node npm install diff --git a/tools/run_tests/run_node.sh b/tools/run_tests/run_node.sh old mode 100644 new mode 100755 index 76f8a1a4f4..0056295949 --- a/tools/run_tests/run_node.sh +++ b/tools/run_tests/run_node.sh @@ -7,4 +7,4 @@ cd $(dirname $0)/../.. root=`pwd` -$root/src/node/node_modules/mocha/bin/mocha $root/node/test +$root/src/node/node_modules/mocha/bin/mocha $root/src/node/test diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index bfe6d7949b..4f2f10f15c 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -68,7 +68,7 @@ class NodeLanguage(object): return ['tools/run_tests/run_node.sh'] def make_targets(self): - return [] + return ['static_c'] def build_steps(self): return [['tools/run_tests/build_node.sh']] @@ -205,7 +205,7 @@ class TestCache(object): def _build_and_run(check_cancelled, newline_on_success, cache): """Do one pass of building & running tests.""" # build latest, sharing cpu between the various makes - if not jobset.run(build_steps): + if not jobset.run(build_steps, maxjobs=1): return 1 # run all the tests -- cgit v1.2.3 From 0343f7f3a663e7c2fc9ad47e4f94c8216b029d74 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 12:04:48 -0800 Subject: Fixes markdown sytax errors --- src/ruby/README.md | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/ruby/README.md b/src/ruby/README.md index 7f7558dc67..7ece7e2706 100755 --- a/src/ruby/README.md +++ b/src/ruby/README.md @@ -14,9 +14,10 @@ INSTALLING ---------- - Install the gRPC core library -TODO: describe this, once the core distribution mechanism is defined. - + TODO: describe this, once the core distribution mechanism is defined. +``` $ gem install grpc +``` Installing from source @@ -24,37 +25,47 @@ Installing from source - Build or Install the gRPC core E.g, from the root of the grpc [git repo](https://github.com/google/grpc) +``` $ cd ../.. $ make && sudo make install +``` - Install Ruby 2.x. Consider doing this with [RVM](http://rvm.io), it's a nice way of controlling the exact ruby version that's used. +``` $ command curl -sSL https://rvm.io/mpapis.asc | gpg --import - $ \curl -sSL https://get.rvm.io | bash -s stable --ruby $ $ # follow the instructions to ensure that your're using the latest stable version of Ruby $ # and that the rvm command is installed +``` - Install [bundler](http://bundler.io/) +``` $ gem install bundler +``` - Finally, install grpc ruby locally. +``` $ cd $ bundle install $ rake # compiles the extension, runs the unit tests, see rake -T for other options - +``` CONTENTS -------- Directory structure is the layout for [ruby extensions](http://guides.rubygems.org/gems-with-extensions/) - * ext: the extension code - * lib: the entrypoint grpc ruby library to be used in a 'require' statement - * spec: tests - * bin: example gRPC clients and servers, e.g, +- ext: + the gRPC ruby extension +- lib: + the entrypoint grpc ruby library to be used in a 'require' statement +- spec: + Rspec unittest +- bin: + example gRPC clients and servers, e.g, ```ruby -# client stub = Math::Math::Stub.new('my.test.math.server.com:8080') req = Math::DivArgs.new(dividend: 7, divisor: 3) logger.info("div(7/3): req=#{req.inspect}") -- cgit v1.2.3 From 0a7d85893c44fee9c76dc72448425a3ef5b7ab97 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 12:30:51 -0800 Subject: Updates rb_server.c to return the created port when it's non-zero --- src/ruby/ext/grpc/rb_server.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c index ef2a9f107b..436d006760 100644 --- a/src/ruby/ext/grpc/rb_server.c +++ b/src/ruby/ext/grpc/rb_server.c @@ -223,7 +223,7 @@ static VALUE grpc_rb_server_add_http2_port(int argc, VALUE *argv, VALUE self) { VALUE port = Qnil; VALUE is_secure = Qnil; grpc_rb_server *s = NULL; - int added_ok = 0; + int recvd_port = 0; /* "11" == 1 mandatory args, 1 (is_secure) is optional */ rb_scan_args(argc, argv, "11", &port, &is_secure); @@ -233,22 +233,22 @@ static VALUE grpc_rb_server_add_http2_port(int argc, VALUE *argv, VALUE self) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; } else if (is_secure == Qnil || TYPE(is_secure) != T_TRUE) { - added_ok = grpc_server_add_http2_port(s->wrapped, StringValueCStr(port)); - if (added_ok == 0) { + recvd_port = grpc_server_add_http2_port(s->wrapped, StringValueCStr(port)); + if (recvd_port == 0) { rb_raise(rb_eRuntimeError, "could not add port %s to server, not sure why", StringValueCStr(port)); } } else if (TYPE(is_secure) != T_FALSE) { - added_ok = + recvd_port = grpc_server_add_secure_http2_port(s->wrapped, StringValueCStr(port)); - if (added_ok == 0) { + if (recvd_port == 0) { rb_raise(rb_eRuntimeError, "could not add secure port %s to server, not sure why", StringValueCStr(port)); } } - return Qnil; + return INT2NUM(recvd_port); } void Init_google_rpc_server() { -- cgit v1.2.3 From 6aa182fb2c0d518335b71c0fb5552342e2d2bee9 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 12:55:47 -0800 Subject: Cleans up some compiler warnings --- src/ruby/ext/grpc/rb_credentials.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ruby/ext/grpc/rb_credentials.c b/src/ruby/ext/grpc/rb_credentials.c index 31f47f3b76..43cc21aeca 100644 --- a/src/ruby/ext/grpc/rb_credentials.c +++ b/src/ruby/ext/grpc/rb_credentials.c @@ -214,6 +214,8 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) { VALUE pem_cert_chain = Qnil; grpc_rb_credentials *wrapper = NULL; grpc_credentials *creds = NULL; + grpc_ssl_pem_key_cert_pair key_cert_pair; + MEMZERO(&key_cert_pair, grpc_ssl_pem_key_cert_pair, 1); /* TODO: Remove mandatory arg when we support default roots. */ /* "12" == 1 mandatory arg, 2 (credentials) is optional */ rb_scan_args(argc, argv, "12", &pem_root_certs, &pem_private_key, @@ -228,8 +230,8 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) { if (pem_private_key == Qnil && pem_cert_chain == Qnil) { creds = grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs), NULL); } else { - grpc_ssl_pem_key_cert_pair key_cert_pair = {RSTRING_PTR(pem_private_key), - RSTRING_PTR(pem_cert_chain)}; + key_cert_pair.private_key = RSTRING_PTR(pem_private_key); + key_cert_pair.cert_chain = RSTRING_PTR(pem_cert_chain); creds = grpc_ssl_credentials_create( RSTRING_PTR(pem_root_certs), &key_cert_pair); } -- cgit v1.2.3 From d3e95a36327c7a2249434e554846c8e44aa7daa0 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 26 Jan 2015 12:57:10 -0800 Subject: Added cancel to surface calls --- src/node/client.js | 8 ++++++++ src/node/surface_client.js | 13 +++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/node/client.js b/src/node/client.js index 7007852b93..a039b0dcfa 100644 --- a/src/node/client.js +++ b/src/node/client.js @@ -160,6 +160,14 @@ GrpcClientStream.prototype._write = function(chunk, encoding, callback) { }, 0); }; +/** + * Cancel the ongoing call. If the call has not already finished, it will finish + * with status CANCELLED. + */ +GrpcClientStream.prototype.cancel = function() { + self._call.cancel(); +}; + /** * Make a request on the channel to the given method with the given arguments * @param {grpc.Channel} channel The channel on which to make the request diff --git a/src/node/surface_client.js b/src/node/surface_client.js index b63ae13e8d..f7123450c2 100644 --- a/src/node/surface_client.js +++ b/src/node/surface_client.js @@ -128,6 +128,16 @@ function _write(chunk, encoding, callback) { */ ClientWritableObjectStream.prototype._write = _write; +/** + * Cancel the underlying call + */ +function cancel() { + this._stream.cancel(); +} + +ClientReadableObjectStream.prototype.cancel = cancel; +ClientWritableObjectStream.prototype.cancel = cancel; + /** * Get a function that can make unary requests to the specified method. * @param {string} method The name of the method to request @@ -155,6 +165,9 @@ function makeUnaryRequestFunction(method, serialize, deserialize) { var stream = client.makeRequest(this.channel, method, serialize, deserialize, metadata, deadline); var emitter = new EventEmitter(); + emitter.cancel = function cancel() { + stream.cancel(); + }; forwardEvent(stream, emitter, 'status'); forwardEvent(stream, emitter, 'metadata'); stream.write(argument); -- cgit v1.2.3 From 666450ef14c31099299567c4d04c526086b31a93 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 26 Jan 2015 13:03:31 -0800 Subject: Updated comment --- tools/run_tests/run_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index 4f2f10f15c..b7248e524b 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -204,7 +204,7 @@ class TestCache(object): def _build_and_run(check_cancelled, newline_on_success, cache): """Do one pass of building & running tests.""" - # build latest, sharing cpu between the various makes + # build latest sequentially if not jobset.run(build_steps, maxjobs=1): return 1 -- cgit v1.2.3 From 8089d966d5e40c5c5ed94632f5db4a9de3f948bc Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 26 Jan 2015 13:58:51 -0800 Subject: Remove clang-format tools Use of these tools is dangerous until such time as we can figure out a standardized clang-format version to use everywhere. --- tools/clang-format/clang-format-all.sh | 9 --------- tools/clang-format/config.sh | 11 ----------- 2 files changed, 20 deletions(-) delete mode 100755 tools/clang-format/clang-format-all.sh delete mode 100644 tools/clang-format/config.sh diff --git a/tools/clang-format/clang-format-all.sh b/tools/clang-format/clang-format-all.sh deleted file mode 100755 index 62228b0b01..0000000000 --- a/tools/clang-format/clang-format-all.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -set -e -source $(dirname $0)/config.sh -cd $(dirname $0)/../.. -for dir in src test include -do - find $dir -name '*.c' -or -name '*.cc' -or -name '*.h' | xargs $CLANG_FORMAT -i -done - diff --git a/tools/clang-format/config.sh b/tools/clang-format/config.sh deleted file mode 100644 index 3adf2678e7..0000000000 --- a/tools/clang-format/config.sh +++ /dev/null @@ -1,11 +0,0 @@ -CLANG_FORMAT=clang-format-3.5 - -set -ex - -if not hash $CLANG_FORMAT 2>/dev/null; then - echo "$CLANG_FORMAT is needed but not installed" - echo "perhaps try:" - echo " sudo apt-get install $CLANG_FORMAT" - exit 1 -fi - -- cgit v1.2.3 From 55dd2ba908fc3cb927d829e24983dc4132e6f558 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 26 Jan 2015 14:11:18 -0800 Subject: Added cancel to client APIs and cancelled event to server APIs --- src/node/client.js | 2 +- src/node/server.js | 1 + src/node/surface_client.js | 10 +++++++ src/node/surface_server.js | 9 +++++++ src/node/test/client_server_test.js | 28 ++++++++++++++++++++ src/node/test/surface_test.js | 53 +++++++++++++++++++++++++++++++++++++ 6 files changed, 102 insertions(+), 1 deletion(-) diff --git a/src/node/client.js b/src/node/client.js index a039b0dcfa..3a1c9eef84 100644 --- a/src/node/client.js +++ b/src/node/client.js @@ -165,7 +165,7 @@ GrpcClientStream.prototype._write = function(chunk, encoding, callback) { * with status CANCELLED. */ GrpcClientStream.prototype.cancel = function() { - self._call.cancel(); + this._call.cancel(); }; /** diff --git a/src/node/server.js b/src/node/server.js index fe50acb5a1..03cdbe6f98 100644 --- a/src/node/server.js +++ b/src/node/server.js @@ -246,6 +246,7 @@ function Server(options) { call.serverAccept(function(event) { if (event.data.code === grpc.status.CANCELLED) { cancelled = true; + stream.emit('cancelled'); } }, 0); call.serverEndInitialMetadata(0); diff --git a/src/node/surface_client.js b/src/node/surface_client.js index f7123450c2..16c31809f4 100644 --- a/src/node/surface_client.js +++ b/src/node/surface_client.js @@ -179,6 +179,11 @@ function makeUnaryRequestFunction(method, serialize, deserialize) { callback(e); } }); + stream.on('status', function forwardStatus(status) { + if (status.code !== client.status.OK) { + callback(status); + } + }); return emitter; } return makeUnaryRequest; @@ -216,6 +221,11 @@ function makeClientStreamRequestFunction(method, serialize, deserialize) { callback(e); } }); + stream.on('status', function forwardStatus(status) { + if (status.code !== client.status.OK) { + callback(status); + } + }); return obj_stream; } return makeClientStreamRequest; diff --git a/src/node/surface_server.js b/src/node/surface_server.js index 07c5339f62..af23ec211c 100644 --- a/src/node/surface_server.js +++ b/src/node/surface_server.js @@ -63,6 +63,9 @@ function ServerReadableObjectStream(stream) { get: function() { return stream.cancelled; } }); var self = this; + this._stream.on('cancelled', function() { + self.emit('cancelled'); + }); this._stream.on('data', function forwardData(chunk) { if (!self.push(chunk)) { self._stream.pause(); @@ -100,6 +103,9 @@ function ServerWritableObjectStream(stream) { var options = {objectMode: true}; Writable.call(this, options); this._stream = stream; + this._stream.on('cancelled', function() { + self.emit('cancelled'); + }); this.on('finish', function() { this._stream.end(); }); @@ -138,6 +144,9 @@ function makeUnaryHandler(handler) { Object.defineProperty(call, 'cancelled', { get: function() { return stream.cancelled;} }); + stream.on('cancelled', function() { + call.emit('cancelled'); + }); handler(call, function sendUnaryData(err, value) { if (err) { stream.emit('error', err); diff --git a/src/node/test/client_server_test.js b/src/node/test/client_server_test.js index 2a25908684..99438a1659 100644 --- a/src/node/test/client_server_test.js +++ b/src/node/test/client_server_test.js @@ -77,6 +77,14 @@ function errorHandler(stream) { }; } +/** + * Wait for a cancellation instead of responding + * @param {Stream} stream + */ +function cancelHandler(stream) { + // do nothing +} + describe('echo client', function() { it('should receive echo responses', function(done) { var server = new Server(); @@ -125,6 +133,26 @@ describe('echo client', function() { done(); }); }); + it('should be able to cancel a call', function(done) { + var server = new Server(); + var port_num = server.bind('0.0.0.0:0'); + server.register('cancellation', cancelHandler); + server.start(); + + var channel = new grpc.Channel('localhost:' + port_num); + var stream = client.makeRequest( + channel, + 'cancellation', + null, + getDeadline(1)); + + stream.cancel(); + stream.on('status', function(status) { + assert.equal(status.code, grpc.status.CANCELLED); + server.shutdown(); + done(); + }); + }); }); /* TODO(mlumish): explore options for reducing duplication between this test * and the insecure echo client test */ diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js index 34f1a156eb..16e4869d83 100644 --- a/src/node/test/surface_test.js +++ b/src/node/test/surface_test.js @@ -35,6 +35,8 @@ var assert = require('assert'); var surface_server = require('../surface_server.js'); +var surface_client = require('../surface_client.js'); + var ProtoBuf = require('protobufjs'); var grpc = require('..'); @@ -73,3 +75,54 @@ describe('Surface server constructor', function() { }, /math.Math/); }); }); +describe('Surface client', function() { + var client; + var server; + before(function() { + var Server = grpc.buildServer([mathService]); + server = new Server({ + 'math.Math': { + 'div': function(stream) {}, + 'divMany': function(stream) {}, + 'fib': function(stream) {}, + 'sum': function(stream) {} + } + }); + var port = server.bind('localhost:0'); + var Client = surface_client.makeClientConstructor(mathService); + client = new Client('localhost:' + port); + }); + after(function() { + server.shutdown(); + }); + it('Should correctly cancel a unary call', function(done) { + var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) { + assert.strictEqual(err.code, surface_client.status.CANCELLED); + done(); + }); + call.cancel(); + }); + it('Should correctly cancel a client stream call', function(done) { + var call = client.sum(function(err, resp) { + assert.strictEqual(err.code, surface_client.status.CANCELLED); + done(); + }); + call.cancel(); + }); + it('Should correctly cancel a server stream call', function(done) { + var call = client.fib({'limit': 5}); + call.on('status', function(status) { + assert.strictEqual(status.code, surface_client.status.CANCELLED); + done(); + }); + call.cancel(); + }); + it('Should correctly cancel a bidi stream call', function(done) { + var call = client.divMany(); + call.on('status', function(status) { + assert.strictEqual(status.code, surface_client.status.CANCELLED); + done(); + }); + call.cancel(); + }); +}); -- cgit v1.2.3 From 4b962f72d34b79e7eec0b226ae03f46a15cb7f04 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 26 Jan 2015 14:31:03 -0800 Subject: Refactored tests to avoid hanging --- src/node/test/call_test.js | 13 ++++++- src/node/test/client_server_test.js | 78 +++++++++++++++++++------------------ 2 files changed, 51 insertions(+), 40 deletions(-) diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js index 6e52ec89bd..b37c44abaf 100644 --- a/src/node/test/call_test.js +++ b/src/node/test/call_test.js @@ -34,8 +34,6 @@ var assert = require('assert'); var grpc = require('bindings')('grpc.node'); -var channel = new grpc.Channel('localhost:7070'); - /** * Helper function to return an absolute deadline given a relative timeout in * seconds. @@ -49,6 +47,17 @@ function getDeadline(timeout_secs) { } describe('call', function() { + var channel; + var server; + before(function() { + server = new grpc.Server(); + var port = server.addHttp2Port('localhost:0'); + server.start(); + channel = new grpc.Channel('localhost:' + port); + }); + after(function() { + server.shutdown(); + }); describe('constructor', function() { it('should reject anything less than 3 arguments', function() { assert.throws(function() { diff --git a/src/node/test/client_server_test.js b/src/node/test/client_server_test.js index 99438a1659..11cc511dc9 100644 --- a/src/node/test/client_server_test.js +++ b/src/node/test/client_server_test.js @@ -86,14 +86,23 @@ function cancelHandler(stream) { } describe('echo client', function() { - it('should receive echo responses', function(done) { - var server = new Server(); + var server; + var channel; + before(function() { + server = new Server(); var port_num = server.bind('0.0.0.0:0'); server.register('echo', echoHandler); + server.register('error', errorHandler); + server.register('cancellation', cancelHandler); server.start(); + channel = new grpc.Channel('localhost:' + port_num); + }); + after(function() { + server.shutdown(); + }); + it('should receive echo responses', function(done) { var messages = ['echo1', 'echo2', 'echo3', 'echo4']; - var channel = new grpc.Channel('localhost:' + port_num); var stream = client.makeRequest( channel, 'echo'); @@ -106,17 +115,10 @@ describe('echo client', function() { index += 1; }); stream.on('end', function() { - server.shutdown(); done(); }); }); it('should get an error status that the server throws', function(done) { - var server = new Server(); - var port_num = server.bind('0.0.0.0:0'); - server.register('error', errorHandler); - server.start(); - - var channel = new grpc.Channel('localhost:' + port_num); var stream = client.makeRequest( channel, 'error', @@ -129,17 +131,10 @@ describe('echo client', function() { stream.on('status', function(status) { assert.equal(status.code, grpc.status.UNIMPLEMENTED); assert.equal(status.details, 'error details'); - server.shutdown(); done(); }); }); it('should be able to cancel a call', function(done) { - var server = new Server(); - var port_num = server.bind('0.0.0.0:0'); - server.register('cancellation', cancelHandler); - server.start(); - - var channel = new grpc.Channel('localhost:' + port_num); var stream = client.makeRequest( channel, 'cancellation', @@ -149,7 +144,6 @@ describe('echo client', function() { stream.cancel(); stream.on('status', function(status) { assert.equal(status.code, grpc.status.CANCELLED); - server.shutdown(); done(); }); }); @@ -157,7 +151,9 @@ describe('echo client', function() { /* TODO(mlumish): explore options for reducing duplication between this test * and the insecure echo client test */ describe('secure echo client', function() { - it('should recieve echo responses', function(done) { + var server; + var channel; + before(function(done) { fs.readFile(ca_path, function(err, ca_data) { assert.ifError(err); fs.readFile(key_path, function(err, key_data) { @@ -169,34 +165,40 @@ describe('secure echo client', function() { key_data, pem_data); - var server = new Server({'credentials' : server_creds}); + server = new Server({'credentials' : server_creds}); var port_num = server.bind('0.0.0.0:0', true); server.register('echo', echoHandler); server.start(); - var messages = ['echo1', 'echo2', 'echo3', 'echo4']; - var channel = new grpc.Channel('localhost:' + port_num, { + channel = new grpc.Channel('localhost:' + port_num, { 'grpc.ssl_target_name_override' : 'foo.test.google.com', 'credentials' : creds }); - var stream = client.makeRequest( - channel, - 'echo'); - - _(messages).map(function(val) { - return new Buffer(val); - }).pipe(stream); - var index = 0; - stream.on('data', function(chunk) { - assert.equal(messages[index], chunk.toString()); - index += 1; - }); - stream.on('end', function() { - server.shutdown(); - done(); - }); + done(); }); }); }); }); + after(function() { + server.shutdown(); + }); + it('should recieve echo responses', function(done) { + var messages = ['echo1', 'echo2', 'echo3', 'echo4']; + var stream = client.makeRequest( + channel, + 'echo'); + + _(messages).map(function(val) { + return new Buffer(val); + }).pipe(stream); + var index = 0; + stream.on('data', function(chunk) { + assert.equal(messages[index], chunk.toString()); + index += 1; + }); + stream.on('end', function() { + server.shutdown(); + done(); + }); + }); }); -- cgit v1.2.3 From d485b13fb89be67acb1925a21b3142db335e0a90 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 26 Jan 2015 14:40:27 -0800 Subject: Refactored other tests --- src/node/test/end_to_end_test.js | 21 +++++++++++---------- src/node/test/server_test.js | 13 +++++++++---- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/node/test/end_to_end_test.js b/src/node/test/end_to_end_test.js index f7ccbcf5f2..f8cb660d2d 100644 --- a/src/node/test/end_to_end_test.js +++ b/src/node/test/end_to_end_test.js @@ -56,14 +56,21 @@ function multiDone(done, count) { } describe('end-to-end', function() { + var server; + var channel; + before(function() { + server = new grpc.Server(); + var port_num = server.addHttp2Port('0.0.0.0:0'); + server.start(); + channel = new grpc.Channel('localhost:' + port_num); + }); + after(function() { + server.shutdown(); + }); it('should start and end a request without error', function(complete) { - var server = new grpc.Server(); var done = multiDone(function() { complete(); - server.shutdown(); }, 2); - var port_num = server.addHttp2Port('0.0.0.0:0'); - var channel = new grpc.Channel('localhost:' + port_num); var deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 3); var status_text = 'xyz'; @@ -81,7 +88,6 @@ describe('end-to-end', function() { done(); }, 0); - server.start(); server.requestCall(function(event) { assert.strictEqual(event.type, grpc.completionType.SERVER_RPC_NEW); var server_call = event.call; @@ -109,13 +115,10 @@ describe('end-to-end', function() { it('should send and receive data without error', function(complete) { var req_text = 'client_request'; var reply_text = 'server_response'; - var server = new grpc.Server(); var done = multiDone(function() { complete(); server.shutdown(); }, 6); - var port_num = server.addHttp2Port('0.0.0.0:0'); - var channel = new grpc.Channel('localhost:' + port_num); var deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 3); var status_text = 'success'; @@ -151,8 +154,6 @@ describe('end-to-end', function() { assert.strictEqual(event.data.toString(), reply_text); done(); }); - - server.start(); server.requestCall(function(event) { assert.strictEqual(event.type, grpc.completionType.SERVER_RPC_NEW); var server_call = event.call; diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js index 457d13d2f5..d0ec1555c6 100644 --- a/src/node/test/server_test.js +++ b/src/node/test/server_test.js @@ -65,17 +65,22 @@ function echoHandler(stream) { } describe('echo server', function() { - it('should echo inputs as responses', function(done) { - done = multiDone(done, 4); - var server = new Server(); + var server; + var channel; + before(function() { + server = new Server(); var port_num = server.bind('[::]:0'); server.register('echo', echoHandler); server.start(); + channel = new grpc.Channel('localhost:' + port_num); + }); + it('should echo inputs as responses', function(done) { + done = multiDone(done, 4); + var req_text = 'echo test string'; var status_text = 'OK'; - var channel = new grpc.Channel('localhost:' + port_num); var deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 3); var call = new grpc.Call(channel, -- cgit v1.2.3 From 64c3e72fec0682355d8ab2798557aa2c022960e1 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Mon, 26 Jan 2015 15:59:27 -0800 Subject: removed string.h reference from build.json --- Makefile | 1 - build.json | 1 - vsprojects/vs2013/gpr.vcxproj | 1 - vsprojects/vs2013/gpr.vcxproj.filters | 3 --- 4 files changed, 6 deletions(-) diff --git a/Makefile b/Makefile index f4bb942b52..74372a6fb8 100644 --- a/Makefile +++ b/Makefile @@ -1233,7 +1233,6 @@ PUBLIC_HEADERS_C += \ include/grpc/support/port_platform.h \ include/grpc/support/slice.h \ include/grpc/support/slice_buffer.h \ - include/grpc/support/string.h \ include/grpc/support/sync.h \ include/grpc/support/sync_generic.h \ include/grpc/support/sync_posix.h \ diff --git a/build.json b/build.json index 4416c3fdd4..dbc8276eb7 100644 --- a/build.json +++ b/build.json @@ -202,7 +202,6 @@ "include/grpc/support/port_platform.h", "include/grpc/support/slice.h", "include/grpc/support/slice_buffer.h", - "include/grpc/support/string.h", "include/grpc/support/sync.h", "include/grpc/support/sync_generic.h", "include/grpc/support/sync_posix.h", diff --git a/vsprojects/vs2013/gpr.vcxproj b/vsprojects/vs2013/gpr.vcxproj index 6075e25ca0..7f05148b88 100644 --- a/vsprojects/vs2013/gpr.vcxproj +++ b/vsprojects/vs2013/gpr.vcxproj @@ -86,7 +86,6 @@ - diff --git a/vsprojects/vs2013/gpr.vcxproj.filters b/vsprojects/vs2013/gpr.vcxproj.filters index c1fccfff3b..38b430f651 100644 --- a/vsprojects/vs2013/gpr.vcxproj.filters +++ b/vsprojects/vs2013/gpr.vcxproj.filters @@ -120,9 +120,6 @@ include\grpc\support - - include\grpc\support - include\grpc\support -- cgit v1.2.3 From 0eaafca3b2fdd0fc03bbeffcd61569f80b4b04c0 Mon Sep 17 00:00:00 2001 From: Donna Dionne Date: Mon, 26 Jan 2015 16:38:10 -0800 Subject: Adding commands to run cloud to prod tests Adding 2 runners to run the test matrix --- tools/gce_setup/cloud_prod_runner.sh | 24 +++++++ tools/gce_setup/grpc_docker.sh | 123 ++++++++++++++++++++++++++++++++- tools/gce_setup/interop_test_runner.sh | 28 ++++++++ 3 files changed, 174 insertions(+), 1 deletion(-) create mode 100755 tools/gce_setup/cloud_prod_runner.sh create mode 100755 tools/gce_setup/interop_test_runner.sh diff --git a/tools/gce_setup/cloud_prod_runner.sh b/tools/gce_setup/cloud_prod_runner.sh new file mode 100755 index 0000000000..0c1163ad7d --- /dev/null +++ b/tools/gce_setup/cloud_prod_runner.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +main() { + source grpc_docker.sh + test_cases=(large_unary empty_unary client_streaming server_streaming) + clients=(cxx java go ruby) + for test_case in "${test_cases[@]}" + do + for client in "${clients[@]}" + do + if grpc_cloud_prod_test $test_case grpc-docker-testclients $client + then + echo "$test_case $client $server passed" >> /tmp/cloud_prod_result.txt + else + echo "$test_case $client $server failed" >> /tmp/cloud_prod_result.txt + fi + done + done + gsutil cp /tmp/cloud_prod_result.txt gs://stoked-keyword-656-output/cloud_prod_result.txt + rm /tmp/cloud_prod_result.txt +} + +set -x +main "$@" diff --git a/tools/gce_setup/grpc_docker.sh b/tools/gce_setup/grpc_docker.sh index d97f829435..3c2c5ae67a 100755 --- a/tools/gce_setup/grpc_docker.sh +++ b/tools/gce_setup/grpc_docker.sh @@ -393,6 +393,53 @@ grpc_interop_test_args() { } } +# checks the positional args and assigns them to variables visible in the caller +# +# these are the positional args passed to grpc_cloud_prod_test after option flags +# are removed +# +# three args are expected, in order +# - test_case +# - host +# - client to run +grpc_cloud_prod_test_args() { + [[ -n $1 ]] && { # test_case + test_case=$1 + shift + } || { + echo "$FUNCNAME: missing arg: test_case" 1>&2 + return 1 + } + + [[ -n $1 ]] && { # host + host=$1 + shift + } || { + echo "$FUNCNAME: missing arg: host" 1>&2 + return 1 + } + + [[ -n $1 ]] && { # client_type + case $1 in + cxx|go|java|nodejs|php|python|ruby) + grpc_gen_test_cmd="grpc_cloud_prod_gen_$1_cmd" + declare -F $grpc_gen_test_cmd >> /dev/null || { + echo "-f: test_func for $1 => $grpc_gen_test_cmd is not defined" 1>&2 + return 2 + } + shift + ;; + *) + echo "bad client_type: $1" 1>&2 + return 1 + ;; + esac + } || { + echo "$FUNCNAME: missing arg: client_type" 1>&2 + return 1 + } +} + _grpc_sync_scripts_args() { grpc_gce_script_root='tools/gce_setup' @@ -622,6 +669,52 @@ grpc_interop_test() { gcloud compute $project_opt ssh $zone_opt $host --command "$cmd" } +# Runs a test command on a docker instance. +# +# call-seq: +# grpc_cloud_prod_test +# +# requirements: +# host is a GCE instance running docker with access to the gRPC docker images +# test_name is one of the named gRPC tests [http://go/grpc_interop_tests] +# client_type is one of [cxx,go,java,php,python,ruby] +# +# it assumes: +# that each grpc-imp has a docker image named grpc/, e.g, grpc/java +# a test is run using $ docker run 'path/to/interop_test_bin --flags' +# the required images are available on +# +# each client_type should have an associated bash func: +# grpc_cloud_prod_gen__cmd +# the func provides the dockerized commmand for running client_type's test. +# If no such func is available, tests for that client type cannot be run. +grpc_cloud_prod_test() { + _grpc_ensure_gcloud_ssh || return 1; + # declare vars local so that they don't pollute the shell environment + # where they this func is used. + + local grpc_zone grpc_project dry_run # set by _grpc_set_project_and_zone + # grpc_cloud_prod_test_args + local test_case host grpc_gen_test_cmd + + # set the project zone and check that all necessary args are provided + _grpc_set_project_and_zone -f grpc_cloud_prod_test_args "$@" || return 1 + gce_has_instance $grpc_project $host || return 1; + + local test_case_flag=" --test_case=$test_case" + cmd=$($grpc_gen_test_cmd $test_case_flag) + [[ -n $cmd ]] || return 1 + + local project_opt="--project $grpc_project" + local zone_opt="--zone $grpc_zone" + local ssh_cmd="bash -l -c \"$cmd\"" + echo "will run:" + echo " $ssh_cmd" + echo "on $host" + [[ $dry_run == 1 ]] && return 0 # don't run the command on a dry run + gcloud compute $project_opt ssh $zone_opt $host --command "$cmd" +} + # constructs the full dockerized ruby interop test cmd. # # call-seq: @@ -655,11 +748,25 @@ grpc_interop_gen_go_cmd() { grpc_interop_gen_java_cmd() { local cmd_prefix="sudo docker run grpc/java"; local test_script="/var/local/git/grpc-java/run-test-client.sh"; - local test_script+=" --server_host_override=foo.test.google.com --use_test_ca=true --use_tls=true" + local test_script+=" --server_host_override=foo.test.google.fr --use_test_ca=true --use_tls=true" local the_cmd="$cmd_prefix $test_script $@"; echo $the_cmd } +# constructs the full dockerized java interop test cmd. +# +# call-seq: +# flags= .... # generic flags to include the command +# cmd=$($grpc_gen_test_cmd $flags) +grpc_cloud_prod_gen_java_cmd() { + local cmd_prefix="sudo docker run grpc/java"; + local test_script="/var/local/git/grpc-java/run-test-client.sh"; + local test_script+=" --use_tls=true" + local gfe_flags=" --server_port=443 --server_host=grpc-test.sandbox.google.com --server_host_override=grpc-test.sandbox.google.com" + local the_cmd="$cmd_prefix $test_script $gfe_flags $@"; + echo $the_cmd +} + # constructs the full dockerized php interop test cmd. # # TODO(mlumish): update this to use the script once that's on git-on-borg @@ -689,4 +796,18 @@ grpc_interop_gen_cxx_cmd() { echo $the_cmd } +# constructs the full dockerized cpp interop test cmd. +# +# +# call-seq: +# flags= .... # generic flags to include the command +# cmd=$($grpc_gen_test_cmd $flags) +grpc_cloud_prod_gen_cxx_cmd() { + local cmd_prefix="sudo docker run grpc/cxx"; + local test_script="/var/local/git/grpc/bins/opt/interop_client --enable_ssl"; + local gfe_flags=" --use_prod_roots --server_port=443 --server_host=grpc-test.sandbox.google.com --server_host_override=grpc-test.sandbox.google.com" + local the_cmd="$cmd_prefix $test_script $gfe_flags $@"; + echo $the_cmd +} + # TODO(grpc-team): add grpc_interop_gen_xxx_cmd for python|cxx|nodejs diff --git a/tools/gce_setup/interop_test_runner.sh b/tools/gce_setup/interop_test_runner.sh new file mode 100755 index 0000000000..cfdb7048fc --- /dev/null +++ b/tools/gce_setup/interop_test_runner.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +main() { + source grpc_docker.sh + test_cases=(large_unary empty unary ping_pong client_streaming server_streaming) + clients=(cxx java go ruby) + servers=(cxx java go ruby) + for test_case in "${test_cases[@]}" + do + for client in "${clients[@]}" + do + for server in "${servers[@]}" + do + if grpc_interop_test $test_case grpc-docker-testclients $client grpc-docker-server $server + then + echo "$test_case $client $server passed" >> /tmp/interop_result.txt + else + echo "$test_case $client $server failed" >> /tmp/interop_result.txt + fi + done + done + done + gsutil cp /tmp/interop_result.txt gs://stoked-keyword-656-output/interop_result.txt + rm /tmp/interop_result.txt +} + +set -x +main "$@" -- cgit v1.2.3 From 75d7f9a3a66f15bc9feed6c235e7b78328f12b4c Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 16:57:33 -0800 Subject: Resolves issues that stopped that stopped tests from running ok --- src/ruby/spec/client_server_spec.rb | 102 ++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 50 deletions(-) diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb index b2afb0581e..ffd021749b 100644 --- a/src/ruby/spec/client_server_spec.rb +++ b/src/ruby/spec/client_server_spec.rb @@ -44,12 +44,13 @@ shared_context 'setup: tags' do before(:example) do @server_finished_tag = Object.new @client_finished_tag = Object.new + @client_metadata_tag = Object.new @server_tag = Object.new @tag = Object.new end def deadline - Time.now + 0.05 + Time.now + 2 end def expect_next_event_on(queue, type, tag) @@ -63,27 +64,30 @@ shared_context 'setup: tags' do ev end - def server_receives_and_responds_with(reply_text) - reply = ByteBuffer.new(reply_text) + def server_allows_client_to_proceed @server.request_call(@server_tag) - ev = @server_queue.pluck(@server_tag, TimeConsts::INFINITE_FUTURE) + ev = @server_queue.pluck(@server_tag, deadline) expect(ev).not_to be_nil expect(ev.type).to be(SERVER_RPC_NEW) - ev.call.server_accept(@server_queue, @server_finished_tag) - ev.call.server_end_initial_metadata - ev.call.start_read(@server_tag) + server_call = ev.call + server_call.server_accept(@server_queue, @server_finished_tag) + server_call.server_end_initial_metadata + server_call + end + + def server_responds_with(server_call, reply_text) + reply = ByteBuffer.new(reply_text) + server_call.start_read(@server_tag) ev = @server_queue.pluck(@server_tag, TimeConsts::INFINITE_FUTURE) expect(ev.type).to be(READ) - ev.call.start_write(reply, @server_tag) + server_call.start_write(reply, @server_tag) ev = @server_queue.pluck(@server_tag, TimeConsts::INFINITE_FUTURE) expect(ev).not_to be_nil expect(ev.type).to be(WRITE_ACCEPTED) - ev.call end def client_sends(call, sent = 'a message') req = ByteBuffer.new(sent) - call.invoke(@client_queue, @tag, @client_finished_tag) call.start_write(req, @tag) ev = @client_queue.pluck(@tag, TimeConsts::INFINITE_FUTURE) expect(ev).not_to be_nil @@ -102,16 +106,20 @@ shared_examples 'basic GRPC message delivery is OK' do it 'servers receive requests from clients and start responding' do reply = ByteBuffer.new('the server payload') call = new_client_call - msg = client_sends(call) + call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) # check the server rpc new was received - @server.request_call(@server_tag) - ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag) + # @server.request_call(@server_tag) + # ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag) # accept the call - server_call = ev.call - server_call.server_accept(@server_queue, @server_finished_tag) - server_call.server_end_initial_metadata + # server_call = ev.call + # server_call.server_accept(@server_queue, @server_finished_tag) + # server_call.server_end_initial_metadata + server_call = server_allows_client_to_proceed + + # client sends a message + msg = client_sends(call) # confirm the server can read the inbound message server_call.start_read(@server_tag) @@ -125,18 +133,19 @@ shared_examples 'basic GRPC message delivery is OK' do it 'responses written by servers are received by the client' do call = new_client_call + call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) + server_call = server_allows_client_to_proceed client_sends(call) - server_receives_and_responds_with('server_response') + server_responds_with(server_call, 'server_response') call.start_read(@tag) - expect_next_event_on(@client_queue, CLIENT_METADATA_READ, @tag) ev = expect_next_event_on(@client_queue, READ, @tag) expect(ev.result.to_s).to eq('server_response') end it 'servers can ignore a client write and send a status' do call = new_client_call - client_sends(call) + call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) # check the server rpc new was received @server.request_call(@server_tag) @@ -150,9 +159,13 @@ shared_examples 'basic GRPC message delivery is OK' do server_call.start_write_status(StatusCodes::NOT_FOUND, 'not found', @server_tag) + # Client sends some data + client_sends(call) + # client gets an empty response for the read, preceeded by some metadata. call.start_read(@tag) - expect_next_event_on(@client_queue, CLIENT_METADATA_READ, @tag) + expect_next_event_on(@client_queue, CLIENT_METADATA_READ, + @client_metadata_tag) ev = expect_next_event_on(@client_queue, READ, @tag) expect(ev.tag).to be(@tag) expect(ev.result.to_s).to eq('') @@ -166,13 +179,14 @@ shared_examples 'basic GRPC message delivery is OK' do it 'completes calls by sending status to client and server' do call = new_client_call + call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) + server_call = server_allows_client_to_proceed client_sends(call) - server_call = server_receives_and_responds_with('server_response') + server_responds_with(server_call, 'server_response') server_call.start_write_status(10_101, 'status code is 10101', @server_tag) # first the client says writes are done call.start_read(@tag) - expect_next_event_on(@client_queue, CLIENT_METADATA_READ, @tag) expect_next_event_on(@client_queue, READ, @tag) call.writes_done(@tag) @@ -215,22 +229,13 @@ shared_examples 'GRPC metadata delivery works OK' do end end - it 'sends an empty hash when no metadata is added' do - call = new_client_call - client_sends(call) - - # Server gets a response - @server.request_call(@server_tag) - expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag) - end - it 'sends all the metadata pairs when keys and values are valid' do @valid_metadata.each do |md| call = new_client_call call.add_metadata(md) # Client begins a call OK - call.invoke(@client_queue, @tag, @client_finished_tag) + call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) # ... server has all metadata available even though the client did not # send a write @@ -262,7 +267,7 @@ shared_examples 'GRPC metadata delivery works OK' do it 'raises an exception if a metadata key is invalid' do @bad_keys.each do |md| call = new_client_call - client_sends(call) + call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) # server gets the invocation @server.request_call(@server_tag) @@ -273,7 +278,7 @@ shared_examples 'GRPC metadata delivery works OK' do it 'sends a hash that contains the status when no metadata is added' do call = new_client_call - client_sends(call) + call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) # server gets the invocation @server.request_call(@server_tag) @@ -284,21 +289,17 @@ shared_examples 'GRPC metadata delivery works OK' do server_call.server_accept(@server_queue, @server_finished_tag) server_call.server_end_initial_metadata - # ... these server sends some data, allowing the metadata read - server_call.start_write(ByteBuffer.new('reply with metadata'), - @server_tag) - expect_next_event_on(@server_queue, WRITE_ACCEPTED, @server_tag) - # there is the HTTP status metadata, though there should not be any # TODO: update this with the bug number to be resolved - ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ, @tag) + ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ, + @client_metadata_tag) expect(ev.result).to eq(':status' => '200') end it 'sends all the pairs and status:200 when keys and values are valid' do @valid_metadata.each do |md| call = new_client_call - client_sends(call) + call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag) # server gets the invocation @server.request_call(@server_tag) @@ -311,7 +312,8 @@ shared_examples 'GRPC metadata delivery works OK' do server_call.server_end_initial_metadata # Now the client can read the metadata - ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ, @tag) + ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ, + @client_metadata_tag) replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }] replace_symbols[':status'] = '200' expect(ev.result).to eq(replace_symbols) @@ -322,17 +324,18 @@ end describe 'the http client/server' do before(:example) do - port = find_unused_tcp_port - host = "localhost:#{port}" + server_host = '0.0.0.0:0' @client_queue = GRPC::Core::CompletionQueue.new @server_queue = GRPC::Core::CompletionQueue.new @server = GRPC::Core::Server.new(@server_queue, nil) - @server.add_http2_port(host) + server_port = @server.add_http2_port(server_host) + puts "Server running on #{server_port}" @server.start - @ch = Channel.new(host, nil) + @ch = Channel.new("0.0.0.0:#{server_port}", nil) end after(:example) do + @ch.close @server.close end @@ -346,16 +349,15 @@ end describe 'the secure http client/server' do before(:example) do certs = load_test_certs - port = find_unused_tcp_port - host = "localhost:#{port}" + server_host = 'localhost:0' @client_queue = GRPC::Core::CompletionQueue.new @server_queue = GRPC::Core::CompletionQueue.new server_creds = GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2]) @server = GRPC::Core::Server.new(@server_queue, nil, server_creds) - @server.add_http2_port(host, true) + server_port = @server.add_http2_port(server_host, true) @server.start args = { Channel::SSL_TARGET => 'foo.test.google.com' } - @ch = Channel.new(host, args, + @ch = Channel.new("localhost:#{server_port}", args, GRPC::Core::Credentials.new(certs[0], nil, nil)) end -- cgit v1.2.3 From b39d91daa8d103fed695863c4be78223b8922212 Mon Sep 17 00:00:00 2001 From: Donna Dionne Date: Mon, 26 Jan 2015 17:00:53 -0800 Subject: Fixing a small typo --- tools/gce_setup/interop_test_runner.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/gce_setup/interop_test_runner.sh b/tools/gce_setup/interop_test_runner.sh index cfdb7048fc..1c0d82095c 100755 --- a/tools/gce_setup/interop_test_runner.sh +++ b/tools/gce_setup/interop_test_runner.sh @@ -2,7 +2,7 @@ main() { source grpc_docker.sh - test_cases=(large_unary empty unary ping_pong client_streaming server_streaming) + test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming) clients=(cxx java go ruby) servers=(cxx java go ruby) for test_case in "${test_cases[@]}" -- cgit v1.2.3 From 0343b10817c96f58ce823ef19c394acff4602f7a Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 17:06:51 -0800 Subject: Updates client_server_spec to use the server_port --- src/ruby/spec/client_server_spec.rb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb index b2afb0581e..c2517d649f 100644 --- a/src/ruby/spec/client_server_spec.rb +++ b/src/ruby/spec/client_server_spec.rb @@ -322,14 +322,13 @@ end describe 'the http client/server' do before(:example) do - port = find_unused_tcp_port - host = "localhost:#{port}" + server_host = 'localhost:0' @client_queue = GRPC::Core::CompletionQueue.new @server_queue = GRPC::Core::CompletionQueue.new @server = GRPC::Core::Server.new(@server_queue, nil) - @server.add_http2_port(host) + server_port = @server.add_http2_port(server_host) @server.start - @ch = Channel.new(host, nil) + @ch = Channel.new("localhost:#{server_port}", nil) end after(:example) do @@ -347,15 +346,15 @@ describe 'the secure http client/server' do before(:example) do certs = load_test_certs port = find_unused_tcp_port - host = "localhost:#{port}" + server_host = 'localhost:0' @client_queue = GRPC::Core::CompletionQueue.new @server_queue = GRPC::Core::CompletionQueue.new server_creds = GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2]) @server = GRPC::Core::Server.new(@server_queue, nil, server_creds) - @server.add_http2_port(host, true) + server_port = @server.add_http2_port(host, true) @server.start args = { Channel::SSL_TARGET => 'foo.test.google.com' } - @ch = Channel.new(host, args, + @ch = Channel.new("localhost:#{server_port}", args, GRPC::Core::Credentials.new(certs[0], nil, nil)) end -- cgit v1.2.3 From 9fbf7e54c29722275d5e8bc0987066004cdd9570 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 26 Jan 2015 17:16:57 -0800 Subject: Moved extension and JS files to separate directories --- src/node/byte_buffer.cc | 79 ------ src/node/byte_buffer.h | 56 ---- src/node/call.cc | 385 -------------------------- src/node/call.h | 82 ------ src/node/channel.cc | 182 ------------ src/node/channel.h | 79 ------ src/node/client.js | 215 -------------- src/node/common.js | 103 ------- src/node/completion_queue_async_worker.cc | 89 ------ src/node/completion_queue_async_worker.h | 79 ------ src/node/credentials.cc | 205 -------------- src/node/credentials.h | 81 ------ src/node/event.cc | 164 ----------- src/node/event.h | 48 ---- src/node/ext/byte_buffer.cc | 79 ++++++ src/node/ext/byte_buffer.h | 56 ++++ src/node/ext/call.cc | 385 ++++++++++++++++++++++++++ src/node/ext/call.h | 82 ++++++ src/node/ext/channel.cc | 182 ++++++++++++ src/node/ext/channel.h | 79 ++++++ src/node/ext/completion_queue_async_worker.cc | 89 ++++++ src/node/ext/completion_queue_async_worker.h | 79 ++++++ src/node/ext/credentials.cc | 205 ++++++++++++++ src/node/ext/credentials.h | 81 ++++++ src/node/ext/event.cc | 164 +++++++++++ src/node/ext/event.h | 48 ++++ src/node/ext/node_grpc.cc | 180 ++++++++++++ src/node/ext/server.cc | 236 ++++++++++++++++ src/node/ext/server.h | 79 ++++++ src/node/ext/server_credentials.cc | 155 +++++++++++ src/node/ext/server_credentials.h | 77 ++++++ src/node/ext/tag.cc | 101 +++++++ src/node/ext/tag.h | 59 ++++ src/node/ext/timeval.cc | 66 +++++ src/node/ext/timeval.h | 48 ++++ src/node/index.js | 108 ++++++++ src/node/main.js | 108 -------- src/node/node_grpc.cc | 180 ------------ src/node/server.cc | 236 ---------------- src/node/server.h | 79 ------ src/node/server.js | 314 --------------------- src/node/server_credentials.cc | 155 ----------- src/node/server_credentials.h | 77 ------ src/node/src/client.js | 215 ++++++++++++++ src/node/src/common.js | 103 +++++++ src/node/src/server.js | 314 +++++++++++++++++++++ src/node/src/surface_client.js | 357 ++++++++++++++++++++++++ src/node/src/surface_server.js | 333 ++++++++++++++++++++++ src/node/surface_client.js | 357 ------------------------ src/node/surface_server.js | 333 ---------------------- src/node/tag.cc | 101 ------- src/node/tag.h | 59 ---- src/node/timeval.cc | 66 ----- src/node/timeval.h | 48 ---- 54 files changed, 3960 insertions(+), 3960 deletions(-) delete mode 100644 src/node/byte_buffer.cc delete mode 100644 src/node/byte_buffer.h delete mode 100644 src/node/call.cc delete mode 100644 src/node/call.h delete mode 100644 src/node/channel.cc delete mode 100644 src/node/channel.h delete mode 100644 src/node/client.js delete mode 100644 src/node/common.js delete mode 100644 src/node/completion_queue_async_worker.cc delete mode 100644 src/node/completion_queue_async_worker.h delete mode 100644 src/node/credentials.cc delete mode 100644 src/node/credentials.h delete mode 100644 src/node/event.cc delete mode 100644 src/node/event.h create mode 100644 src/node/ext/byte_buffer.cc create mode 100644 src/node/ext/byte_buffer.h create mode 100644 src/node/ext/call.cc create mode 100644 src/node/ext/call.h create mode 100644 src/node/ext/channel.cc create mode 100644 src/node/ext/channel.h create mode 100644 src/node/ext/completion_queue_async_worker.cc create mode 100644 src/node/ext/completion_queue_async_worker.h create mode 100644 src/node/ext/credentials.cc create mode 100644 src/node/ext/credentials.h create mode 100644 src/node/ext/event.cc create mode 100644 src/node/ext/event.h create mode 100644 src/node/ext/node_grpc.cc create mode 100644 src/node/ext/server.cc create mode 100644 src/node/ext/server.h create mode 100644 src/node/ext/server_credentials.cc create mode 100644 src/node/ext/server_credentials.h create mode 100644 src/node/ext/tag.cc create mode 100644 src/node/ext/tag.h create mode 100644 src/node/ext/timeval.cc create mode 100644 src/node/ext/timeval.h create mode 100644 src/node/index.js delete mode 100644 src/node/main.js delete mode 100644 src/node/node_grpc.cc delete mode 100644 src/node/server.cc delete mode 100644 src/node/server.h delete mode 100644 src/node/server.js delete mode 100644 src/node/server_credentials.cc delete mode 100644 src/node/server_credentials.h create mode 100644 src/node/src/client.js create mode 100644 src/node/src/common.js create mode 100644 src/node/src/server.js create mode 100644 src/node/src/surface_client.js create mode 100644 src/node/src/surface_server.js delete mode 100644 src/node/surface_client.js delete mode 100644 src/node/surface_server.js delete mode 100644 src/node/tag.cc delete mode 100644 src/node/tag.h delete mode 100644 src/node/timeval.cc delete mode 100644 src/node/timeval.h diff --git a/src/node/byte_buffer.cc b/src/node/byte_buffer.cc deleted file mode 100644 index 142951475a..0000000000 --- a/src/node/byte_buffer.cc +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include - -#include -#include -#include "grpc/grpc.h" -#include "grpc/support/slice.h" - -namespace grpc { -namespace node { - -#include "byte_buffer.h" - -using ::node::Buffer; -using v8::Handle; -using v8::Value; - -grpc_byte_buffer *BufferToByteBuffer(Handle buffer) { - NanScope(); - int length = Buffer::Length(buffer); - char *data = Buffer::Data(buffer); - gpr_slice slice = gpr_slice_malloc(length); - memcpy(GPR_SLICE_START_PTR(slice), data, length); - grpc_byte_buffer *byte_buffer(grpc_byte_buffer_create(&slice, 1)); - gpr_slice_unref(slice); - return byte_buffer; -} - -Handle ByteBufferToBuffer(grpc_byte_buffer *buffer) { - NanEscapableScope(); - if (buffer == NULL) { - NanReturnNull(); - } - size_t length = grpc_byte_buffer_length(buffer); - char *result = reinterpret_cast(calloc(length, sizeof(char))); - size_t offset = 0; - grpc_byte_buffer_reader *reader = grpc_byte_buffer_reader_create(buffer); - gpr_slice next; - while (grpc_byte_buffer_reader_next(reader, &next) != 0) { - memcpy(result + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next)); - offset += GPR_SLICE_LENGTH(next); - } - return NanEscapeScope(NanNewBufferHandle(result, length)); -} -} // namespace node -} // namespace grpc diff --git a/src/node/byte_buffer.h b/src/node/byte_buffer.h deleted file mode 100644 index ee2b4c0d15..0000000000 --- a/src/node/byte_buffer.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef NET_GRPC_NODE_BYTE_BUFFER_H_ -#define NET_GRPC_NODE_BYTE_BUFFER_H_ - -#include - -#include -#include -#include "grpc/grpc.h" - -namespace grpc { -namespace node { - -/* Convert a Node.js Buffer to grpc_byte_buffer. Requires that - ::node::Buffer::HasInstance(buffer) */ -grpc_byte_buffer *BufferToByteBuffer(v8::Handle buffer); - -/* Convert a grpc_byte_buffer to a Node.js Buffer */ -v8::Handle ByteBufferToBuffer(grpc_byte_buffer *buffer); - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_BYTE_BUFFER_H_ diff --git a/src/node/call.cc b/src/node/call.cc deleted file mode 100644 index 6434c2f0d5..0000000000 --- a/src/node/call.cc +++ /dev/null @@ -1,385 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#include "grpc/grpc.h" -#include "grpc/support/time.h" -#include "byte_buffer.h" -#include "call.h" -#include "channel.h" -#include "completion_queue_async_worker.h" -#include "timeval.h" -#include "tag.h" - -namespace grpc { -namespace node { - -using ::node::Buffer; -using v8::Arguments; -using v8::Array; -using v8::Exception; -using v8::External; -using v8::Function; -using v8::FunctionTemplate; -using v8::Handle; -using v8::HandleScope; -using v8::Integer; -using v8::Local; -using v8::Number; -using v8::Object; -using v8::ObjectTemplate; -using v8::Persistent; -using v8::Uint32; -using v8::String; -using v8::Value; - -Persistent Call::constructor; -Persistent Call::fun_tpl; - -Call::Call(grpc_call *call) : wrapped_call(call) {} - -Call::~Call() { grpc_call_destroy(wrapped_call); } - -void Call::Init(Handle exports) { - NanScope(); - Local tpl = FunctionTemplate::New(New); - tpl->SetClassName(NanNew("Call")); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - NanSetPrototypeTemplate(tpl, "addMetadata", - FunctionTemplate::New(AddMetadata)->GetFunction()); - NanSetPrototypeTemplate(tpl, "invoke", - FunctionTemplate::New(Invoke)->GetFunction()); - NanSetPrototypeTemplate(tpl, "serverAccept", - FunctionTemplate::New(ServerAccept)->GetFunction()); - NanSetPrototypeTemplate( - tpl, "serverEndInitialMetadata", - FunctionTemplate::New(ServerEndInitialMetadata)->GetFunction()); - NanSetPrototypeTemplate(tpl, "cancel", - FunctionTemplate::New(Cancel)->GetFunction()); - NanSetPrototypeTemplate(tpl, "startWrite", - FunctionTemplate::New(StartWrite)->GetFunction()); - NanSetPrototypeTemplate( - tpl, "startWriteStatus", - FunctionTemplate::New(StartWriteStatus)->GetFunction()); - NanSetPrototypeTemplate(tpl, "writesDone", - FunctionTemplate::New(WritesDone)->GetFunction()); - NanSetPrototypeTemplate(tpl, "startReadMetadata", - FunctionTemplate::New(WritesDone)->GetFunction()); - NanSetPrototypeTemplate(tpl, "startRead", - FunctionTemplate::New(StartRead)->GetFunction()); - NanAssignPersistent(fun_tpl, tpl); - NanAssignPersistent(constructor, tpl->GetFunction()); - constructor->Set(NanNew("WRITE_BUFFER_HINT"), - NanNew(GRPC_WRITE_BUFFER_HINT)); - constructor->Set(NanNew("WRITE_NO_COMPRESS"), - NanNew(GRPC_WRITE_NO_COMPRESS)); - exports->Set(String::NewSymbol("Call"), constructor); -} - -bool Call::HasInstance(Handle val) { - NanScope(); - return NanHasInstance(fun_tpl, val); -} - -Handle Call::WrapStruct(grpc_call *call) { - NanEscapableScope(); - if (call == NULL) { - return NanEscapeScope(NanNull()); - } - const int argc = 1; - Handle argv[argc] = {External::New(reinterpret_cast(call))}; - return NanEscapeScope(constructor->NewInstance(argc, argv)); -} - -NAN_METHOD(Call::New) { - NanScope(); - - if (args.IsConstructCall()) { - Call *call; - if (args[0]->IsExternal()) { - // This option is used for wrapping an existing call - grpc_call *call_value = - reinterpret_cast(External::Unwrap(args[0])); - call = new Call(call_value); - } else { - if (!Channel::HasInstance(args[0])) { - return NanThrowTypeError("Call's first argument must be a Channel"); - } - if (!args[1]->IsString()) { - return NanThrowTypeError("Call's second argument must be a string"); - } - if (!(args[2]->IsNumber() || args[2]->IsDate())) { - return NanThrowTypeError( - "Call's third argument must be a date or a number"); - } - Handle channel_object = args[0]->ToObject(); - Channel *channel = ObjectWrap::Unwrap(channel_object); - if (channel->GetWrappedChannel() == NULL) { - return NanThrowError("Call cannot be created from a closed channel"); - } - NanUtf8String method(args[1]); - double deadline = args[2]->NumberValue(); - grpc_channel *wrapped_channel = channel->GetWrappedChannel(); - grpc_call *wrapped_call = - grpc_channel_create_call(wrapped_channel, *method, channel->GetHost(), - MillisecondsToTimespec(deadline)); - call = new Call(wrapped_call); - args.This()->SetHiddenValue(String::NewSymbol("channel_"), - channel_object); - } - call->Wrap(args.This()); - NanReturnValue(args.This()); - } else { - const int argc = 4; - Local argv[argc] = {args[0], args[1], args[2], args[3]}; - NanReturnValue(constructor->NewInstance(argc, argv)); - } -} - -NAN_METHOD(Call::AddMetadata) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError("addMetadata can only be called on Call objects"); - } - Call *call = ObjectWrap::Unwrap(args.This()); - for (int i = 0; !args[i]->IsUndefined(); i++) { - if (!args[i]->IsObject()) { - return NanThrowTypeError( - "addMetadata arguments must be objects with key and value"); - } - Handle item = args[i]->ToObject(); - Handle key = item->Get(NanNew("key")); - if (!key->IsString()) { - return NanThrowTypeError( - "objects passed to addMetadata must have key->string"); - } - Handle value = item->Get(NanNew("value")); - if (!Buffer::HasInstance(value)) { - return NanThrowTypeError( - "objects passed to addMetadata must have value->Buffer"); - } - grpc_metadata metadata; - NanUtf8String utf8_key(key); - metadata.key = *utf8_key; - metadata.value = Buffer::Data(value); - metadata.value_length = Buffer::Length(value); - grpc_call_error error = - grpc_call_add_metadata(call->wrapped_call, &metadata, 0); - if (error != GRPC_CALL_OK) { - return NanThrowError("addMetadata failed", error); - } - } - NanReturnUndefined(); -} - -NAN_METHOD(Call::Invoke) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError("invoke can only be called on Call objects"); - } - if (!args[0]->IsFunction()) { - return NanThrowTypeError("invoke's first argument must be a function"); - } - if (!args[1]->IsFunction()) { - return NanThrowTypeError("invoke's second argument must be a function"); - } - if (!args[2]->IsUint32()) { - return NanThrowTypeError("invoke's third argument must be integer flags"); - } - Call *call = ObjectWrap::Unwrap(args.This()); - unsigned int flags = args[3]->Uint32Value(); - grpc_call_error error = grpc_call_invoke( - call->wrapped_call, CompletionQueueAsyncWorker::GetQueue(), - CreateTag(args[0], args.This()), CreateTag(args[1], args.This()), flags); - if (error == GRPC_CALL_OK) { - CompletionQueueAsyncWorker::Next(); - CompletionQueueAsyncWorker::Next(); - } else { - return NanThrowError("invoke failed", error); - } - NanReturnUndefined(); -} - -NAN_METHOD(Call::ServerAccept) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError("accept can only be called on Call objects"); - } - if (!args[0]->IsFunction()) { - return NanThrowTypeError("accept's first argument must be a function"); - } - Call *call = ObjectWrap::Unwrap(args.This()); - grpc_call_error error = grpc_call_server_accept( - call->wrapped_call, CompletionQueueAsyncWorker::GetQueue(), - CreateTag(args[0], args.This())); - if (error == GRPC_CALL_OK) { - CompletionQueueAsyncWorker::Next(); - } else { - return NanThrowError("serverAccept failed", error); - } - NanReturnUndefined(); -} - -NAN_METHOD(Call::ServerEndInitialMetadata) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError( - "serverEndInitialMetadata can only be called on Call objects"); - } - if (!args[0]->IsUint32()) { - return NanThrowTypeError( - "serverEndInitialMetadata's second argument must be integer flags"); - } - Call *call = ObjectWrap::Unwrap(args.This()); - unsigned int flags = args[1]->Uint32Value(); - grpc_call_error error = - grpc_call_server_end_initial_metadata(call->wrapped_call, flags); - if (error != GRPC_CALL_OK) { - return NanThrowError("serverEndInitialMetadata failed", error); - } - NanReturnUndefined(); -} - -NAN_METHOD(Call::Cancel) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError("cancel can only be called on Call objects"); - } - Call *call = ObjectWrap::Unwrap(args.This()); - grpc_call_error error = grpc_call_cancel(call->wrapped_call); - if (error != GRPC_CALL_OK) { - return NanThrowError("cancel failed", error); - } - NanReturnUndefined(); -} - -NAN_METHOD(Call::StartWrite) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError("startWrite can only be called on Call objects"); - } - if (!Buffer::HasInstance(args[0])) { - return NanThrowTypeError("startWrite's first argument must be a Buffer"); - } - if (!args[1]->IsFunction()) { - return NanThrowTypeError("startWrite's second argument must be a function"); - } - if (!args[2]->IsUint32()) { - return NanThrowTypeError( - "startWrite's third argument must be integer flags"); - } - Call *call = ObjectWrap::Unwrap(args.This()); - grpc_byte_buffer *buffer = BufferToByteBuffer(args[0]); - unsigned int flags = args[2]->Uint32Value(); - grpc_call_error error = grpc_call_start_write( - call->wrapped_call, buffer, CreateTag(args[1], args.This()), flags); - if (error == GRPC_CALL_OK) { - CompletionQueueAsyncWorker::Next(); - } else { - return NanThrowError("startWrite failed", error); - } - NanReturnUndefined(); -} - -NAN_METHOD(Call::StartWriteStatus) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError( - "startWriteStatus can only be called on Call objects"); - } - if (!args[0]->IsUint32()) { - return NanThrowTypeError( - "startWriteStatus's first argument must be a status code"); - } - if (!args[1]->IsString()) { - return NanThrowTypeError( - "startWriteStatus's second argument must be a string"); - } - if (!args[2]->IsFunction()) { - return NanThrowTypeError( - "startWriteStatus's third argument must be a function"); - } - Call *call = ObjectWrap::Unwrap(args.This()); - NanUtf8String details(args[1]); - grpc_call_error error = grpc_call_start_write_status( - call->wrapped_call, (grpc_status_code)args[0]->Uint32Value(), *details, - CreateTag(args[2], args.This())); - if (error == GRPC_CALL_OK) { - CompletionQueueAsyncWorker::Next(); - } else { - return NanThrowError("startWriteStatus failed", error); - } - NanReturnUndefined(); -} - -NAN_METHOD(Call::WritesDone) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError("writesDone can only be called on Call objects"); - } - if (!args[0]->IsFunction()) { - return NanThrowTypeError("writesDone's first argument must be a function"); - } - Call *call = ObjectWrap::Unwrap(args.This()); - grpc_call_error error = grpc_call_writes_done( - call->wrapped_call, CreateTag(args[0], args.This())); - if (error == GRPC_CALL_OK) { - CompletionQueueAsyncWorker::Next(); - } else { - return NanThrowError("writesDone failed", error); - } - NanReturnUndefined(); -} - -NAN_METHOD(Call::StartRead) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError("startRead can only be called on Call objects"); - } - if (!args[0]->IsFunction()) { - return NanThrowTypeError("startRead's first argument must be a function"); - } - Call *call = ObjectWrap::Unwrap(args.This()); - grpc_call_error error = - grpc_call_start_read(call->wrapped_call, CreateTag(args[0], args.This())); - if (error == GRPC_CALL_OK) { - CompletionQueueAsyncWorker::Next(); - } else { - return NanThrowError("startRead failed", error); - } - NanReturnUndefined(); -} - -} // namespace node -} // namespace grpc diff --git a/src/node/call.h b/src/node/call.h deleted file mode 100644 index 1924a1bf42..0000000000 --- a/src/node/call.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef NET_GRPC_NODE_CALL_H_ -#define NET_GRPC_NODE_CALL_H_ - -#include -#include -#include "grpc/grpc.h" - -#include "channel.h" - -namespace grpc { -namespace node { - -/* Wrapper class for grpc_call structs. */ -class Call : public ::node::ObjectWrap { - public: - static void Init(v8::Handle exports); - static bool HasInstance(v8::Handle val); - /* Wrap a grpc_call struct in a javascript object */ - static v8::Handle WrapStruct(grpc_call *call); - - private: - explicit Call(grpc_call *call); - ~Call(); - - // Prevent copying - Call(const Call &); - Call &operator=(const Call &); - - static NAN_METHOD(New); - static NAN_METHOD(AddMetadata); - static NAN_METHOD(Invoke); - static NAN_METHOD(ServerAccept); - static NAN_METHOD(ServerEndInitialMetadata); - static NAN_METHOD(Cancel); - static NAN_METHOD(StartWrite); - static NAN_METHOD(StartWriteStatus); - static NAN_METHOD(WritesDone); - static NAN_METHOD(StartRead); - static v8::Persistent constructor; - // Used for typechecking instances of this javascript class - static v8::Persistent fun_tpl; - - grpc_call *wrapped_call; -}; - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_CALL_H_ diff --git a/src/node/channel.cc b/src/node/channel.cc deleted file mode 100644 index 9087d6f919..0000000000 --- a/src/node/channel.cc +++ /dev/null @@ -1,182 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#include - -#include -#include -#include "grpc/grpc.h" -#include "grpc/grpc_security.h" -#include "channel.h" -#include "credentials.h" - -namespace grpc { -namespace node { - -using v8::Arguments; -using v8::Array; -using v8::Exception; -using v8::Function; -using v8::FunctionTemplate; -using v8::Handle; -using v8::HandleScope; -using v8::Integer; -using v8::Local; -using v8::Object; -using v8::Persistent; -using v8::String; -using v8::Value; - -Persistent Channel::constructor; -Persistent Channel::fun_tpl; - -Channel::Channel(grpc_channel *channel, NanUtf8String *host) - : wrapped_channel(channel), host(host) {} - -Channel::~Channel() { - if (wrapped_channel != NULL) { - grpc_channel_destroy(wrapped_channel); - } - delete host; -} - -void Channel::Init(Handle exports) { - NanScope(); - Local tpl = FunctionTemplate::New(New); - tpl->SetClassName(NanNew("Channel")); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - NanSetPrototypeTemplate(tpl, "close", - FunctionTemplate::New(Close)->GetFunction()); - NanAssignPersistent(fun_tpl, tpl); - NanAssignPersistent(constructor, tpl->GetFunction()); - exports->Set(NanNew("Channel"), constructor); -} - -bool Channel::HasInstance(Handle val) { - NanScope(); - return NanHasInstance(fun_tpl, val); -} - -grpc_channel *Channel::GetWrappedChannel() { return this->wrapped_channel; } - -char *Channel::GetHost() { return **this->host; } - -NAN_METHOD(Channel::New) { - NanScope(); - - if (args.IsConstructCall()) { - if (!args[0]->IsString()) { - return NanThrowTypeError("Channel expects a string and an object"); - } - grpc_channel *wrapped_channel; - // Owned by the Channel object - NanUtf8String *host = new NanUtf8String(args[0]); - if (args[1]->IsUndefined()) { - wrapped_channel = grpc_channel_create(**host, NULL); - } else if (args[1]->IsObject()) { - grpc_credentials *creds = NULL; - Handle args_hash(args[1]->ToObject()->Clone()); - if (args_hash->HasOwnProperty(NanNew("credentials"))) { - Handle creds_value = args_hash->Get(NanNew("credentials")); - if (!Credentials::HasInstance(creds_value)) { - return NanThrowTypeError( - "credentials arg must be a Credentials object"); - } - Credentials *creds_object = - ObjectWrap::Unwrap(creds_value->ToObject()); - creds = creds_object->GetWrappedCredentials(); - args_hash->Delete(NanNew("credentials")); - } - Handle keys(args_hash->GetOwnPropertyNames()); - grpc_channel_args channel_args; - channel_args.num_args = keys->Length(); - channel_args.args = reinterpret_cast( - calloc(channel_args.num_args, sizeof(grpc_arg))); - /* These are used to keep all strings until then end of the block, then - destroy them */ - std::vector key_strings(keys->Length()); - std::vector value_strings(keys->Length()); - for (unsigned int i = 0; i < channel_args.num_args; i++) { - Handle current_key(keys->Get(i)->ToString()); - Handle current_value(args_hash->Get(current_key)); - key_strings[i] = new NanUtf8String(current_key); - channel_args.args[i].key = **key_strings[i]; - if (current_value->IsInt32()) { - channel_args.args[i].type = GRPC_ARG_INTEGER; - channel_args.args[i].value.integer = current_value->Int32Value(); - } else if (current_value->IsString()) { - channel_args.args[i].type = GRPC_ARG_STRING; - value_strings[i] = new NanUtf8String(current_value); - channel_args.args[i].value.string = **value_strings[i]; - } else { - free(channel_args.args); - return NanThrowTypeError("Arg values must be strings"); - } - } - if (creds == NULL) { - wrapped_channel = grpc_channel_create(**host, &channel_args); - } else { - wrapped_channel = - grpc_secure_channel_create(creds, **host, &channel_args); - } - free(channel_args.args); - } else { - return NanThrowTypeError("Channel expects a string and an object"); - } - Channel *channel = new Channel(wrapped_channel, host); - channel->Wrap(args.This()); - NanReturnValue(args.This()); - } else { - const int argc = 2; - Local argv[argc] = {args[0], args[1]}; - NanReturnValue(constructor->NewInstance(argc, argv)); - } -} - -NAN_METHOD(Channel::Close) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError("close can only be called on Channel objects"); - } - Channel *channel = ObjectWrap::Unwrap(args.This()); - if (channel->wrapped_channel != NULL) { - grpc_channel_destroy(channel->wrapped_channel); - channel->wrapped_channel = NULL; - } - NanReturnUndefined(); -} - -} // namespace node -} // namespace grpc diff --git a/src/node/channel.h b/src/node/channel.h deleted file mode 100644 index 140cbf201a..0000000000 --- a/src/node/channel.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef NET_GRPC_NODE_CHANNEL_H_ -#define NET_GRPC_NODE_CHANNEL_H_ - -#include -#include -#include "grpc/grpc.h" - -namespace grpc { -namespace node { - -/* Wrapper class for grpc_channel structs */ -class Channel : public ::node::ObjectWrap { - public: - static void Init(v8::Handle exports); - static bool HasInstance(v8::Handle val); - /* This is used to typecheck javascript objects before converting them to - this type */ - static v8::Persistent prototype; - - /* Returns the grpc_channel struct that this object wraps */ - grpc_channel *GetWrappedChannel(); - - /* Return the hostname that this channel connects to */ - char *GetHost(); - - private: - explicit Channel(grpc_channel *channel, NanUtf8String *host); - ~Channel(); - - // Prevent copying - Channel(const Channel &); - Channel &operator=(const Channel &); - - static NAN_METHOD(New); - static NAN_METHOD(Close); - static v8::Persistent constructor; - static v8::Persistent fun_tpl; - - grpc_channel *wrapped_channel; - NanUtf8String *host; -}; - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_CHANNEL_H_ diff --git a/src/node/client.js b/src/node/client.js deleted file mode 100644 index 3a1c9eef84..0000000000 --- a/src/node/client.js +++ /dev/null @@ -1,215 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -var grpc = require('bindings')('grpc.node'); - -var common = require('./common'); - -var Duplex = require('stream').Duplex; -var util = require('util'); - -util.inherits(GrpcClientStream, Duplex); - -/** - * Class for representing a gRPC client side stream as a Node stream. Extends - * from stream.Duplex. - * @constructor - * @param {grpc.Call} call Call object to proxy - * @param {function(*):Buffer=} serialize Serialization function for requests - * @param {function(Buffer):*=} deserialize Deserialization function for - * responses - */ -function GrpcClientStream(call, serialize, deserialize) { - Duplex.call(this, {objectMode: true}); - if (!serialize) { - serialize = function(value) { - return value; - }; - } - if (!deserialize) { - deserialize = function(value) { - return value; - }; - } - var self = this; - var finished = false; - // Indicates that a read is currently pending - var reading = false; - // Indicates that a write is currently pending - var writing = false; - this._call = call; - - /** - * Serialize a request value to a buffer. Always maps null to null. Otherwise - * uses the provided serialize function - * @param {*} value The value to serialize - * @return {Buffer} The serialized value - */ - this.serialize = function(value) { - if (value === null || value === undefined) { - return null; - } - return serialize(value); - }; - - /** - * Deserialize a response buffer to a value. Always maps null to null. - * Otherwise uses the provided deserialize function. - * @param {Buffer} buffer The buffer to deserialize - * @return {*} The deserialized value - */ - this.deserialize = function(buffer) { - if (buffer === null) { - return null; - } - return deserialize(buffer); - }; - /** - * Callback to be called when a READ event is received. Pushes the data onto - * the read queue and starts reading again if applicable - * @param {grpc.Event} event READ event object - */ - function readCallback(event) { - if (finished) { - self.push(null); - return; - } - var data = event.data; - if (self.push(self.deserialize(data)) && data != null) { - self._call.startRead(readCallback); - } else { - reading = false; - } - } - call.invoke(function(event) { - self.emit('metadata', event.data); - }, function(event) { - finished = true; - self.emit('status', event.data); - }, 0); - this.on('finish', function() { - call.writesDone(function() {}); - }); - /** - * Start reading if there is not already a pending read. Reading will - * continue until self.push returns false (indicating reads should slow - * down) or the read data is null (indicating that there is no more data). - */ - this.startReading = function() { - if (finished) { - self.push(null); - } else { - if (!reading) { - reading = true; - self._call.startRead(readCallback); - } - } - }; -} - -/** - * Start reading. This is an implementation of a method needed for implementing - * stream.Readable. - * @param {number} size Ignored - */ -GrpcClientStream.prototype._read = function(size) { - this.startReading(); -}; - -/** - * Attempt to write the given chunk. Calls the callback when done. This is an - * implementation of a method needed for implementing stream.Writable. - * @param {Buffer} chunk The chunk to write - * @param {string} encoding Ignored - * @param {function(Error=)} callback Ignored - */ -GrpcClientStream.prototype._write = function(chunk, encoding, callback) { - var self = this; - self._call.startWrite(self.serialize(chunk), function(event) { - callback(); - }, 0); -}; - -/** - * Cancel the ongoing call. If the call has not already finished, it will finish - * with status CANCELLED. - */ -GrpcClientStream.prototype.cancel = function() { - this._call.cancel(); -}; - -/** - * Make a request on the channel to the given method with the given arguments - * @param {grpc.Channel} channel The channel on which to make the request - * @param {string} method The method to request - * @param {function(*):Buffer} serialize Serialization function for requests - * @param {function(Buffer):*} deserialize Deserialization function for - * responses - * @param {array=} metadata Array of metadata key/value pairs to add to the call - * @param {(number|Date)=} deadline The deadline for processing this request. - * Defaults to infinite future. - * @return {stream=} The stream of responses - */ -function makeRequest(channel, - method, - serialize, - deserialize, - metadata, - deadline) { - if (deadline === undefined) { - deadline = Infinity; - } - var call = new grpc.Call(channel, method, deadline); - if (metadata) { - call.addMetadata(metadata); - } - return new GrpcClientStream(call, serialize, deserialize); -} - -/** - * See documentation for makeRequest above - */ -exports.makeRequest = makeRequest; - -/** - * Represents a client side gRPC channel associated with a single host. - */ -exports.Channel = grpc.Channel; -/** - * Status name to code number mapping - */ -exports.status = grpc.status; -/** - * Call error name to code number mapping - */ -exports.callError = grpc.callError; diff --git a/src/node/common.js b/src/node/common.js deleted file mode 100644 index 54247e3fa1..0000000000 --- a/src/node/common.js +++ /dev/null @@ -1,103 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -var capitalize = require('underscore.string/capitalize'); - -/** - * Get a function that deserializes a specific type of protobuf. - * @param {function()} cls The constructor of the message type to deserialize - * @return {function(Buffer):cls} The deserialization function - */ -function deserializeCls(cls) { - /** - * Deserialize a buffer to a message object - * @param {Buffer} arg_buf The buffer to deserialize - * @return {cls} The resulting object - */ - return function deserialize(arg_buf) { - return cls.decode(arg_buf); - }; -} - -/** - * 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) { - /** - * Serialize an object to a Buffer - * @param {Object} arg The object to serialize - * @return {Buffer} The serialized object - */ - return function serialize(arg) { - return new Buffer(new Cls(arg).encode().toBuffer()); - }; -} - -/** - * 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) { - if (value === null || value === undefined) { - return ''; - } - var name = value.name; - if (value.className === 'Service.RPCMethod') { - name = capitalize(name); - } - if (value.hasOwnProperty('parent')) { - var parent_name = fullyQualifiedName(value.parent); - if (parent_name !== '') { - name = parent_name + '.' + name; - } - } - return name; -} - -/** - * See docs for deserializeCls - */ -exports.deserializeCls = deserializeCls; - -/** - * See docs for serializeCls - */ -exports.serializeCls = serializeCls; - -/** - * See docs for fullyQualifiedName - */ -exports.fullyQualifiedName = fullyQualifiedName; diff --git a/src/node/completion_queue_async_worker.cc b/src/node/completion_queue_async_worker.cc deleted file mode 100644 index 8de7db66d5..0000000000 --- a/src/node/completion_queue_async_worker.cc +++ /dev/null @@ -1,89 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include - -#include "grpc/grpc.h" -#include "grpc/support/time.h" -#include "completion_queue_async_worker.h" -#include "event.h" -#include "tag.h" - -namespace grpc { -namespace node { - -using v8::Function; -using v8::Handle; -using v8::Object; -using v8::Persistent; -using v8::Value; - -grpc_completion_queue *CompletionQueueAsyncWorker::queue; - -CompletionQueueAsyncWorker::CompletionQueueAsyncWorker() - : NanAsyncWorker(NULL) {} - -CompletionQueueAsyncWorker::~CompletionQueueAsyncWorker() {} - -void CompletionQueueAsyncWorker::Execute() { - result = grpc_completion_queue_next(queue, gpr_inf_future); -} - -grpc_completion_queue *CompletionQueueAsyncWorker::GetQueue() { return queue; } - -void CompletionQueueAsyncWorker::Next() { - NanScope(); - CompletionQueueAsyncWorker *worker = new CompletionQueueAsyncWorker(); - NanAsyncQueueWorker(worker); -} - -void CompletionQueueAsyncWorker::Init(Handle exports) { - NanScope(); - queue = grpc_completion_queue_create(); -} - -void CompletionQueueAsyncWorker::HandleOKCallback() { - NanScope(); - NanCallback event_callback(GetTagHandle(result->tag).As()); - Handle argv[] = {CreateEventObject(result)}; - - DestroyTag(result->tag); - grpc_event_finish(result); - result = NULL; - - event_callback.Call(1, argv); -} - -} // namespace node -} // namespace grpc diff --git a/src/node/completion_queue_async_worker.h b/src/node/completion_queue_async_worker.h deleted file mode 100644 index 2c928b7024..0000000000 --- a/src/node/completion_queue_async_worker.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef NET_GRPC_NODE_COMPLETION_QUEUE_ASYNC_WORKER_H_ -#define NET_GRPC_NODE_COMPLETION_QUEUE_ASYNC_WORKER_H_ -#include - -#include "grpc/grpc.h" - -namespace grpc { -namespace node { - -/* A worker that asynchronously calls completion_queue_next, and queues onto the - node event loop a call to the function stored in the event's tag. */ -class CompletionQueueAsyncWorker : public NanAsyncWorker { - public: - CompletionQueueAsyncWorker(); - - ~CompletionQueueAsyncWorker(); - /* Calls completion_queue_next with the provided deadline, and stores the - event if there was one or sets an error message if there was not */ - void Execute(); - - /* Returns the completion queue attached to this class */ - static grpc_completion_queue *GetQueue(); - - /* Convenience function to create a worker with the given arguments and queue - it to run asynchronously */ - static void Next(); - - /* Initialize the CompletionQueueAsyncWorker class */ - static void Init(v8::Handle exports); - - protected: - /* Called when Execute has succeeded (completed without setting an error - message). Calls the saved callback with the event that came from - completion_queue_next */ - void HandleOKCallback(); - - private: - grpc_event *result; - - static grpc_completion_queue *queue; -}; - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_COMPLETION_QUEUE_ASYNC_WORKER_H_ diff --git a/src/node/credentials.cc b/src/node/credentials.cc deleted file mode 100644 index f9cd2fcfe0..0000000000 --- a/src/node/credentials.cc +++ /dev/null @@ -1,205 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#include "grpc/grpc.h" -#include "grpc/grpc_security.h" -#include "grpc/support/log.h" -#include "credentials.h" - -namespace grpc { -namespace node { - -using ::node::Buffer; -using v8::Arguments; -using v8::Exception; -using v8::External; -using v8::Function; -using v8::FunctionTemplate; -using v8::Handle; -using v8::HandleScope; -using v8::Integer; -using v8::Local; -using v8::Object; -using v8::ObjectTemplate; -using v8::Persistent; -using v8::Value; - -Persistent Credentials::constructor; -Persistent Credentials::fun_tpl; - -Credentials::Credentials(grpc_credentials *credentials) - : wrapped_credentials(credentials) {} - -Credentials::~Credentials() { - gpr_log(GPR_DEBUG, "Destroying credentials object"); - grpc_credentials_release(wrapped_credentials); -} - -void Credentials::Init(Handle exports) { - NanScope(); - Local tpl = FunctionTemplate::New(New); - tpl->SetClassName(NanNew("Credentials")); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - NanAssignPersistent(fun_tpl, tpl); - NanAssignPersistent(constructor, tpl->GetFunction()); - constructor->Set(NanNew("createDefault"), - FunctionTemplate::New(CreateDefault)->GetFunction()); - constructor->Set(NanNew("createSsl"), - FunctionTemplate::New(CreateSsl)->GetFunction()); - constructor->Set(NanNew("createComposite"), - FunctionTemplate::New(CreateComposite)->GetFunction()); - constructor->Set(NanNew("createGce"), - FunctionTemplate::New(CreateGce)->GetFunction()); - constructor->Set(NanNew("createFake"), - FunctionTemplate::New(CreateFake)->GetFunction()); - constructor->Set(NanNew("createIam"), - FunctionTemplate::New(CreateIam)->GetFunction()); - exports->Set(NanNew("Credentials"), constructor); -} - -bool Credentials::HasInstance(Handle val) { - NanScope(); - return NanHasInstance(fun_tpl, val); -} - -Handle Credentials::WrapStruct(grpc_credentials *credentials) { - NanEscapableScope(); - if (credentials == NULL) { - return NanEscapeScope(NanNull()); - } - const int argc = 1; - Handle argv[argc] = { - External::New(reinterpret_cast(credentials))}; - return NanEscapeScope(constructor->NewInstance(argc, argv)); -} - -grpc_credentials *Credentials::GetWrappedCredentials() { - return wrapped_credentials; -} - -NAN_METHOD(Credentials::New) { - NanScope(); - - if (args.IsConstructCall()) { - if (!args[0]->IsExternal()) { - return NanThrowTypeError( - "Credentials can only be created with the provided functions"); - } - grpc_credentials *creds_value = - reinterpret_cast(External::Unwrap(args[0])); - Credentials *credentials = new Credentials(creds_value); - credentials->Wrap(args.This()); - NanReturnValue(args.This()); - } else { - const int argc = 1; - Local argv[argc] = {args[0]}; - NanReturnValue(constructor->NewInstance(argc, argv)); - } -} - -NAN_METHOD(Credentials::CreateDefault) { - NanScope(); - NanReturnValue(WrapStruct(grpc_default_credentials_create())); -} - -NAN_METHOD(Credentials::CreateSsl) { - NanScope(); - char *root_certs = NULL; - grpc_ssl_pem_key_cert_pair key_cert_pair = {NULL, NULL}; - if (Buffer::HasInstance(args[0])) { - root_certs = Buffer::Data(args[0]); - } else if (!(args[0]->IsNull() || args[0]->IsUndefined())) { - return NanThrowTypeError("createSsl's first argument must be a Buffer"); - } - if (Buffer::HasInstance(args[1])) { - key_cert_pair.private_key = Buffer::Data(args[1]); - } else if (!(args[1]->IsNull() || args[1]->IsUndefined())) { - return NanThrowTypeError( - "createSSl's second argument must be a Buffer if provided"); - } - if (Buffer::HasInstance(args[2])) { - key_cert_pair.cert_chain = Buffer::Data(args[2]); - } else if (!(args[2]->IsNull() || args[2]->IsUndefined())) { - return NanThrowTypeError( - "createSSl's third argument must be a Buffer if provided"); - } - - NanReturnValue(WrapStruct(grpc_ssl_credentials_create( - root_certs, - key_cert_pair.private_key == NULL ? NULL : &key_cert_pair))); -} - -NAN_METHOD(Credentials::CreateComposite) { - NanScope(); - if (!HasInstance(args[0])) { - return NanThrowTypeError( - "createComposite's first argument must be a Credentials object"); - } - if (!HasInstance(args[1])) { - return NanThrowTypeError( - "createComposite's second argument must be a Credentials object"); - } - Credentials *creds1 = ObjectWrap::Unwrap(args[0]->ToObject()); - Credentials *creds2 = ObjectWrap::Unwrap(args[1]->ToObject()); - NanReturnValue(WrapStruct(grpc_composite_credentials_create( - creds1->wrapped_credentials, creds2->wrapped_credentials))); -} - -NAN_METHOD(Credentials::CreateGce) { - NanScope(); - 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()) { - return NanThrowTypeError("createIam's first argument must be a string"); - } - if (!args[1]->IsString()) { - return NanThrowTypeError("createIam's second argument must be a string"); - } - NanUtf8String auth_token(args[0]); - NanUtf8String auth_selector(args[1]); - NanReturnValue( - WrapStruct(grpc_iam_credentials_create(*auth_token, *auth_selector))); -} - -} // namespace node -} // namespace grpc diff --git a/src/node/credentials.h b/src/node/credentials.h deleted file mode 100644 index 981e5a99bc..0000000000 --- a/src/node/credentials.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef NET_GRPC_NODE_CREDENTIALS_H_ -#define NET_GRPC_NODE_CREDENTIALS_H_ - -#include -#include -#include "grpc/grpc.h" -#include "grpc/grpc_security.h" - -namespace grpc { -namespace node { - -/* Wrapper class for grpc_credentials structs */ -class Credentials : public ::node::ObjectWrap { - public: - static void Init(v8::Handle exports); - static bool HasInstance(v8::Handle val); - /* Wrap a grpc_credentials struct in a javascript object */ - static v8::Handle WrapStruct(grpc_credentials *credentials); - - /* Returns the grpc_credentials struct that this object wraps */ - grpc_credentials *GetWrappedCredentials(); - - private: - explicit Credentials(grpc_credentials *credentials); - ~Credentials(); - - // Prevent copying - Credentials(const Credentials &); - Credentials &operator=(const Credentials &); - - static NAN_METHOD(New); - static NAN_METHOD(CreateDefault); - static NAN_METHOD(CreateSsl); - static NAN_METHOD(CreateComposite); - static NAN_METHOD(CreateGce); - static NAN_METHOD(CreateFake); - static NAN_METHOD(CreateIam); - static v8::Persistent constructor; - // Used for typechecking instances of this javascript class - static v8::Persistent fun_tpl; - - grpc_credentials *wrapped_credentials; -}; - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_CREDENTIALS_H_ diff --git a/src/node/event.cc b/src/node/event.cc deleted file mode 100644 index 2ca38b7448..0000000000 --- a/src/node/event.cc +++ /dev/null @@ -1,164 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include "grpc/grpc.h" -#include "byte_buffer.h" -#include "call.h" -#include "event.h" -#include "tag.h" -#include "timeval.h" - -namespace grpc { -namespace node { - -using v8::Array; -using v8::Date; -using v8::Handle; -using v8::HandleScope; -using v8::Number; -using v8::Object; -using v8::Persistent; -using v8::String; -using v8::Value; - -Handle GetEventData(grpc_event *event) { - NanEscapableScope(); - size_t count; - grpc_metadata *items; - Handle metadata; - Handle status; - Handle rpc_new; - switch (event->type) { - case GRPC_READ: - return NanEscapeScope(ByteBufferToBuffer(event->data.read)); - case GRPC_INVOKE_ACCEPTED: - return NanEscapeScope(NanNew(event->data.invoke_accepted)); - case GRPC_WRITE_ACCEPTED: - return NanEscapeScope(NanNew(event->data.write_accepted)); - case GRPC_FINISH_ACCEPTED: - return NanEscapeScope(NanNew(event->data.finish_accepted)); - case GRPC_CLIENT_METADATA_READ: - count = event->data.client_metadata_read.count; - items = event->data.client_metadata_read.elements; - metadata = NanNew(static_cast(count)); - for (unsigned int i = 0; i < count; i++) { - Handle item_obj = NanNew(); - item_obj->Set(NanNew("key"), - NanNew(items[i].key)); - item_obj->Set( - NanNew("value"), - NanNew(items[i].value, - static_cast(items[i].value_length))); - metadata->Set(i, item_obj); - } - return NanEscapeScope(metadata); - case GRPC_FINISHED: - status = NanNew(); - status->Set(NanNew("code"), NanNew(event->data.finished.status)); - if (event->data.finished.details != NULL) { - status->Set(NanNew("details"), - String::New(event->data.finished.details)); - } - count = event->data.finished.metadata_count; - items = event->data.finished.metadata_elements; - metadata = NanNew(static_cast(count)); - for (unsigned int i = 0; i < count; i++) { - Handle item_obj = NanNew(); - item_obj->Set(NanNew("key"), - NanNew(items[i].key)); - item_obj->Set( - NanNew("value"), - NanNew(items[i].value, - static_cast(items[i].value_length))); - metadata->Set(i, item_obj); - } - status->Set(NanNew("metadata"), metadata); - return NanEscapeScope(status); - case GRPC_SERVER_RPC_NEW: - rpc_new = NanNew(); - if (event->data.server_rpc_new.method == NULL) { - return NanEscapeScope(NanNull()); - } - rpc_new->Set( - NanNew("method"), - NanNew(event->data.server_rpc_new.method)); - rpc_new->Set( - NanNew("host"), - NanNew(event->data.server_rpc_new.host)); - rpc_new->Set(NanNew("absolute_deadline"), - NanNew(TimespecToMilliseconds( - event->data.server_rpc_new.deadline))); - count = event->data.server_rpc_new.metadata_count; - items = event->data.server_rpc_new.metadata_elements; - metadata = NanNew(static_cast(count)); - for (unsigned int i = 0; i < count; i++) { - Handle item_obj = Object::New(); - item_obj->Set(NanNew("key"), - NanNew(items[i].key)); - item_obj->Set( - NanNew("value"), - NanNew(items[i].value, - static_cast(items[i].value_length))); - metadata->Set(i, item_obj); - } - rpc_new->Set(NanNew("metadata"), metadata); - return NanEscapeScope(rpc_new); - default: - return NanEscapeScope(NanNull()); - } -} - -Handle CreateEventObject(grpc_event *event) { - NanEscapableScope(); - if (event == NULL) { - return NanEscapeScope(NanNull()); - } - Handle event_obj = NanNew(); - Handle call; - if (TagHasCall(event->tag)) { - call = TagGetCall(event->tag); - } else { - call = Call::WrapStruct(event->call); - } - event_obj->Set(NanNew("call"), call); - event_obj->Set(NanNew("type"), - NanNew(event->type)); - event_obj->Set(NanNew("data"), GetEventData(event)); - - return NanEscapeScope(event_obj); -} - -} // namespace node -} // namespace grpc diff --git a/src/node/event.h b/src/node/event.h deleted file mode 100644 index e06d8f0168..0000000000 --- a/src/node/event.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef NET_GRPC_NODE_EVENT_H_ -#define NET_GRPC_NODE_EVENT_H_ - -#include -#include "grpc/grpc.h" - -namespace grpc { -namespace node { - -v8::Handle CreateEventObject(grpc_event *event); - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_EVENT_H_ diff --git a/src/node/ext/byte_buffer.cc b/src/node/ext/byte_buffer.cc new file mode 100644 index 0000000000..142951475a --- /dev/null +++ b/src/node/ext/byte_buffer.cc @@ -0,0 +1,79 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include +#include +#include "grpc/grpc.h" +#include "grpc/support/slice.h" + +namespace grpc { +namespace node { + +#include "byte_buffer.h" + +using ::node::Buffer; +using v8::Handle; +using v8::Value; + +grpc_byte_buffer *BufferToByteBuffer(Handle buffer) { + NanScope(); + int length = Buffer::Length(buffer); + char *data = Buffer::Data(buffer); + gpr_slice slice = gpr_slice_malloc(length); + memcpy(GPR_SLICE_START_PTR(slice), data, length); + grpc_byte_buffer *byte_buffer(grpc_byte_buffer_create(&slice, 1)); + gpr_slice_unref(slice); + return byte_buffer; +} + +Handle ByteBufferToBuffer(grpc_byte_buffer *buffer) { + NanEscapableScope(); + if (buffer == NULL) { + NanReturnNull(); + } + size_t length = grpc_byte_buffer_length(buffer); + char *result = reinterpret_cast(calloc(length, sizeof(char))); + size_t offset = 0; + grpc_byte_buffer_reader *reader = grpc_byte_buffer_reader_create(buffer); + gpr_slice next; + while (grpc_byte_buffer_reader_next(reader, &next) != 0) { + memcpy(result + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next)); + offset += GPR_SLICE_LENGTH(next); + } + return NanEscapeScope(NanNewBufferHandle(result, length)); +} +} // namespace node +} // namespace grpc diff --git a/src/node/ext/byte_buffer.h b/src/node/ext/byte_buffer.h new file mode 100644 index 0000000000..ee2b4c0d15 --- /dev/null +++ b/src/node/ext/byte_buffer.h @@ -0,0 +1,56 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef NET_GRPC_NODE_BYTE_BUFFER_H_ +#define NET_GRPC_NODE_BYTE_BUFFER_H_ + +#include + +#include +#include +#include "grpc/grpc.h" + +namespace grpc { +namespace node { + +/* Convert a Node.js Buffer to grpc_byte_buffer. Requires that + ::node::Buffer::HasInstance(buffer) */ +grpc_byte_buffer *BufferToByteBuffer(v8::Handle buffer); + +/* Convert a grpc_byte_buffer to a Node.js Buffer */ +v8::Handle ByteBufferToBuffer(grpc_byte_buffer *buffer); + +} // namespace node +} // namespace grpc + +#endif // NET_GRPC_NODE_BYTE_BUFFER_H_ diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc new file mode 100644 index 0000000000..6434c2f0d5 --- /dev/null +++ b/src/node/ext/call.cc @@ -0,0 +1,385 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include "grpc/grpc.h" +#include "grpc/support/time.h" +#include "byte_buffer.h" +#include "call.h" +#include "channel.h" +#include "completion_queue_async_worker.h" +#include "timeval.h" +#include "tag.h" + +namespace grpc { +namespace node { + +using ::node::Buffer; +using v8::Arguments; +using v8::Array; +using v8::Exception; +using v8::External; +using v8::Function; +using v8::FunctionTemplate; +using v8::Handle; +using v8::HandleScope; +using v8::Integer; +using v8::Local; +using v8::Number; +using v8::Object; +using v8::ObjectTemplate; +using v8::Persistent; +using v8::Uint32; +using v8::String; +using v8::Value; + +Persistent Call::constructor; +Persistent Call::fun_tpl; + +Call::Call(grpc_call *call) : wrapped_call(call) {} + +Call::~Call() { grpc_call_destroy(wrapped_call); } + +void Call::Init(Handle exports) { + NanScope(); + Local tpl = FunctionTemplate::New(New); + tpl->SetClassName(NanNew("Call")); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + NanSetPrototypeTemplate(tpl, "addMetadata", + FunctionTemplate::New(AddMetadata)->GetFunction()); + NanSetPrototypeTemplate(tpl, "invoke", + FunctionTemplate::New(Invoke)->GetFunction()); + NanSetPrototypeTemplate(tpl, "serverAccept", + FunctionTemplate::New(ServerAccept)->GetFunction()); + NanSetPrototypeTemplate( + tpl, "serverEndInitialMetadata", + FunctionTemplate::New(ServerEndInitialMetadata)->GetFunction()); + NanSetPrototypeTemplate(tpl, "cancel", + FunctionTemplate::New(Cancel)->GetFunction()); + NanSetPrototypeTemplate(tpl, "startWrite", + FunctionTemplate::New(StartWrite)->GetFunction()); + NanSetPrototypeTemplate( + tpl, "startWriteStatus", + FunctionTemplate::New(StartWriteStatus)->GetFunction()); + NanSetPrototypeTemplate(tpl, "writesDone", + FunctionTemplate::New(WritesDone)->GetFunction()); + NanSetPrototypeTemplate(tpl, "startReadMetadata", + FunctionTemplate::New(WritesDone)->GetFunction()); + NanSetPrototypeTemplate(tpl, "startRead", + FunctionTemplate::New(StartRead)->GetFunction()); + NanAssignPersistent(fun_tpl, tpl); + NanAssignPersistent(constructor, tpl->GetFunction()); + constructor->Set(NanNew("WRITE_BUFFER_HINT"), + NanNew(GRPC_WRITE_BUFFER_HINT)); + constructor->Set(NanNew("WRITE_NO_COMPRESS"), + NanNew(GRPC_WRITE_NO_COMPRESS)); + exports->Set(String::NewSymbol("Call"), constructor); +} + +bool Call::HasInstance(Handle val) { + NanScope(); + return NanHasInstance(fun_tpl, val); +} + +Handle Call::WrapStruct(grpc_call *call) { + NanEscapableScope(); + if (call == NULL) { + return NanEscapeScope(NanNull()); + } + const int argc = 1; + Handle argv[argc] = {External::New(reinterpret_cast(call))}; + return NanEscapeScope(constructor->NewInstance(argc, argv)); +} + +NAN_METHOD(Call::New) { + NanScope(); + + if (args.IsConstructCall()) { + Call *call; + if (args[0]->IsExternal()) { + // This option is used for wrapping an existing call + grpc_call *call_value = + reinterpret_cast(External::Unwrap(args[0])); + call = new Call(call_value); + } else { + if (!Channel::HasInstance(args[0])) { + return NanThrowTypeError("Call's first argument must be a Channel"); + } + if (!args[1]->IsString()) { + return NanThrowTypeError("Call's second argument must be a string"); + } + if (!(args[2]->IsNumber() || args[2]->IsDate())) { + return NanThrowTypeError( + "Call's third argument must be a date or a number"); + } + Handle channel_object = args[0]->ToObject(); + Channel *channel = ObjectWrap::Unwrap(channel_object); + if (channel->GetWrappedChannel() == NULL) { + return NanThrowError("Call cannot be created from a closed channel"); + } + NanUtf8String method(args[1]); + double deadline = args[2]->NumberValue(); + grpc_channel *wrapped_channel = channel->GetWrappedChannel(); + grpc_call *wrapped_call = + grpc_channel_create_call(wrapped_channel, *method, channel->GetHost(), + MillisecondsToTimespec(deadline)); + call = new Call(wrapped_call); + args.This()->SetHiddenValue(String::NewSymbol("channel_"), + channel_object); + } + call->Wrap(args.This()); + NanReturnValue(args.This()); + } else { + const int argc = 4; + Local argv[argc] = {args[0], args[1], args[2], args[3]}; + NanReturnValue(constructor->NewInstance(argc, argv)); + } +} + +NAN_METHOD(Call::AddMetadata) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError("addMetadata can only be called on Call objects"); + } + Call *call = ObjectWrap::Unwrap(args.This()); + for (int i = 0; !args[i]->IsUndefined(); i++) { + if (!args[i]->IsObject()) { + return NanThrowTypeError( + "addMetadata arguments must be objects with key and value"); + } + Handle item = args[i]->ToObject(); + Handle key = item->Get(NanNew("key")); + if (!key->IsString()) { + return NanThrowTypeError( + "objects passed to addMetadata must have key->string"); + } + Handle value = item->Get(NanNew("value")); + if (!Buffer::HasInstance(value)) { + return NanThrowTypeError( + "objects passed to addMetadata must have value->Buffer"); + } + grpc_metadata metadata; + NanUtf8String utf8_key(key); + metadata.key = *utf8_key; + metadata.value = Buffer::Data(value); + metadata.value_length = Buffer::Length(value); + grpc_call_error error = + grpc_call_add_metadata(call->wrapped_call, &metadata, 0); + if (error != GRPC_CALL_OK) { + return NanThrowError("addMetadata failed", error); + } + } + NanReturnUndefined(); +} + +NAN_METHOD(Call::Invoke) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError("invoke can only be called on Call objects"); + } + if (!args[0]->IsFunction()) { + return NanThrowTypeError("invoke's first argument must be a function"); + } + if (!args[1]->IsFunction()) { + return NanThrowTypeError("invoke's second argument must be a function"); + } + if (!args[2]->IsUint32()) { + return NanThrowTypeError("invoke's third argument must be integer flags"); + } + Call *call = ObjectWrap::Unwrap(args.This()); + unsigned int flags = args[3]->Uint32Value(); + grpc_call_error error = grpc_call_invoke( + call->wrapped_call, CompletionQueueAsyncWorker::GetQueue(), + CreateTag(args[0], args.This()), CreateTag(args[1], args.This()), flags); + if (error == GRPC_CALL_OK) { + CompletionQueueAsyncWorker::Next(); + CompletionQueueAsyncWorker::Next(); + } else { + return NanThrowError("invoke failed", error); + } + NanReturnUndefined(); +} + +NAN_METHOD(Call::ServerAccept) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError("accept can only be called on Call objects"); + } + if (!args[0]->IsFunction()) { + return NanThrowTypeError("accept's first argument must be a function"); + } + Call *call = ObjectWrap::Unwrap(args.This()); + grpc_call_error error = grpc_call_server_accept( + call->wrapped_call, CompletionQueueAsyncWorker::GetQueue(), + CreateTag(args[0], args.This())); + if (error == GRPC_CALL_OK) { + CompletionQueueAsyncWorker::Next(); + } else { + return NanThrowError("serverAccept failed", error); + } + NanReturnUndefined(); +} + +NAN_METHOD(Call::ServerEndInitialMetadata) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError( + "serverEndInitialMetadata can only be called on Call objects"); + } + if (!args[0]->IsUint32()) { + return NanThrowTypeError( + "serverEndInitialMetadata's second argument must be integer flags"); + } + Call *call = ObjectWrap::Unwrap(args.This()); + unsigned int flags = args[1]->Uint32Value(); + grpc_call_error error = + grpc_call_server_end_initial_metadata(call->wrapped_call, flags); + if (error != GRPC_CALL_OK) { + return NanThrowError("serverEndInitialMetadata failed", error); + } + NanReturnUndefined(); +} + +NAN_METHOD(Call::Cancel) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError("cancel can only be called on Call objects"); + } + Call *call = ObjectWrap::Unwrap(args.This()); + grpc_call_error error = grpc_call_cancel(call->wrapped_call); + if (error != GRPC_CALL_OK) { + return NanThrowError("cancel failed", error); + } + NanReturnUndefined(); +} + +NAN_METHOD(Call::StartWrite) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError("startWrite can only be called on Call objects"); + } + if (!Buffer::HasInstance(args[0])) { + return NanThrowTypeError("startWrite's first argument must be a Buffer"); + } + if (!args[1]->IsFunction()) { + return NanThrowTypeError("startWrite's second argument must be a function"); + } + if (!args[2]->IsUint32()) { + return NanThrowTypeError( + "startWrite's third argument must be integer flags"); + } + Call *call = ObjectWrap::Unwrap(args.This()); + grpc_byte_buffer *buffer = BufferToByteBuffer(args[0]); + unsigned int flags = args[2]->Uint32Value(); + grpc_call_error error = grpc_call_start_write( + call->wrapped_call, buffer, CreateTag(args[1], args.This()), flags); + if (error == GRPC_CALL_OK) { + CompletionQueueAsyncWorker::Next(); + } else { + return NanThrowError("startWrite failed", error); + } + NanReturnUndefined(); +} + +NAN_METHOD(Call::StartWriteStatus) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError( + "startWriteStatus can only be called on Call objects"); + } + if (!args[0]->IsUint32()) { + return NanThrowTypeError( + "startWriteStatus's first argument must be a status code"); + } + if (!args[1]->IsString()) { + return NanThrowTypeError( + "startWriteStatus's second argument must be a string"); + } + if (!args[2]->IsFunction()) { + return NanThrowTypeError( + "startWriteStatus's third argument must be a function"); + } + Call *call = ObjectWrap::Unwrap(args.This()); + NanUtf8String details(args[1]); + grpc_call_error error = grpc_call_start_write_status( + call->wrapped_call, (grpc_status_code)args[0]->Uint32Value(), *details, + CreateTag(args[2], args.This())); + if (error == GRPC_CALL_OK) { + CompletionQueueAsyncWorker::Next(); + } else { + return NanThrowError("startWriteStatus failed", error); + } + NanReturnUndefined(); +} + +NAN_METHOD(Call::WritesDone) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError("writesDone can only be called on Call objects"); + } + if (!args[0]->IsFunction()) { + return NanThrowTypeError("writesDone's first argument must be a function"); + } + Call *call = ObjectWrap::Unwrap(args.This()); + grpc_call_error error = grpc_call_writes_done( + call->wrapped_call, CreateTag(args[0], args.This())); + if (error == GRPC_CALL_OK) { + CompletionQueueAsyncWorker::Next(); + } else { + return NanThrowError("writesDone failed", error); + } + NanReturnUndefined(); +} + +NAN_METHOD(Call::StartRead) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError("startRead can only be called on Call objects"); + } + if (!args[0]->IsFunction()) { + return NanThrowTypeError("startRead's first argument must be a function"); + } + Call *call = ObjectWrap::Unwrap(args.This()); + grpc_call_error error = + grpc_call_start_read(call->wrapped_call, CreateTag(args[0], args.This())); + if (error == GRPC_CALL_OK) { + CompletionQueueAsyncWorker::Next(); + } else { + return NanThrowError("startRead failed", error); + } + NanReturnUndefined(); +} + +} // namespace node +} // namespace grpc diff --git a/src/node/ext/call.h b/src/node/ext/call.h new file mode 100644 index 0000000000..1924a1bf42 --- /dev/null +++ b/src/node/ext/call.h @@ -0,0 +1,82 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef NET_GRPC_NODE_CALL_H_ +#define NET_GRPC_NODE_CALL_H_ + +#include +#include +#include "grpc/grpc.h" + +#include "channel.h" + +namespace grpc { +namespace node { + +/* Wrapper class for grpc_call structs. */ +class Call : public ::node::ObjectWrap { + public: + static void Init(v8::Handle exports); + static bool HasInstance(v8::Handle val); + /* Wrap a grpc_call struct in a javascript object */ + static v8::Handle WrapStruct(grpc_call *call); + + private: + explicit Call(grpc_call *call); + ~Call(); + + // Prevent copying + Call(const Call &); + Call &operator=(const Call &); + + static NAN_METHOD(New); + static NAN_METHOD(AddMetadata); + static NAN_METHOD(Invoke); + static NAN_METHOD(ServerAccept); + static NAN_METHOD(ServerEndInitialMetadata); + static NAN_METHOD(Cancel); + static NAN_METHOD(StartWrite); + static NAN_METHOD(StartWriteStatus); + static NAN_METHOD(WritesDone); + static NAN_METHOD(StartRead); + static v8::Persistent constructor; + // Used for typechecking instances of this javascript class + static v8::Persistent fun_tpl; + + grpc_call *wrapped_call; +}; + +} // namespace node +} // namespace grpc + +#endif // NET_GRPC_NODE_CALL_H_ diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc new file mode 100644 index 0000000000..9087d6f919 --- /dev/null +++ b/src/node/ext/channel.cc @@ -0,0 +1,182 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include + +#include +#include +#include "grpc/grpc.h" +#include "grpc/grpc_security.h" +#include "channel.h" +#include "credentials.h" + +namespace grpc { +namespace node { + +using v8::Arguments; +using v8::Array; +using v8::Exception; +using v8::Function; +using v8::FunctionTemplate; +using v8::Handle; +using v8::HandleScope; +using v8::Integer; +using v8::Local; +using v8::Object; +using v8::Persistent; +using v8::String; +using v8::Value; + +Persistent Channel::constructor; +Persistent Channel::fun_tpl; + +Channel::Channel(grpc_channel *channel, NanUtf8String *host) + : wrapped_channel(channel), host(host) {} + +Channel::~Channel() { + if (wrapped_channel != NULL) { + grpc_channel_destroy(wrapped_channel); + } + delete host; +} + +void Channel::Init(Handle exports) { + NanScope(); + Local tpl = FunctionTemplate::New(New); + tpl->SetClassName(NanNew("Channel")); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + NanSetPrototypeTemplate(tpl, "close", + FunctionTemplate::New(Close)->GetFunction()); + NanAssignPersistent(fun_tpl, tpl); + NanAssignPersistent(constructor, tpl->GetFunction()); + exports->Set(NanNew("Channel"), constructor); +} + +bool Channel::HasInstance(Handle val) { + NanScope(); + return NanHasInstance(fun_tpl, val); +} + +grpc_channel *Channel::GetWrappedChannel() { return this->wrapped_channel; } + +char *Channel::GetHost() { return **this->host; } + +NAN_METHOD(Channel::New) { + NanScope(); + + if (args.IsConstructCall()) { + if (!args[0]->IsString()) { + return NanThrowTypeError("Channel expects a string and an object"); + } + grpc_channel *wrapped_channel; + // Owned by the Channel object + NanUtf8String *host = new NanUtf8String(args[0]); + if (args[1]->IsUndefined()) { + wrapped_channel = grpc_channel_create(**host, NULL); + } else if (args[1]->IsObject()) { + grpc_credentials *creds = NULL; + Handle args_hash(args[1]->ToObject()->Clone()); + if (args_hash->HasOwnProperty(NanNew("credentials"))) { + Handle creds_value = args_hash->Get(NanNew("credentials")); + if (!Credentials::HasInstance(creds_value)) { + return NanThrowTypeError( + "credentials arg must be a Credentials object"); + } + Credentials *creds_object = + ObjectWrap::Unwrap(creds_value->ToObject()); + creds = creds_object->GetWrappedCredentials(); + args_hash->Delete(NanNew("credentials")); + } + Handle keys(args_hash->GetOwnPropertyNames()); + grpc_channel_args channel_args; + channel_args.num_args = keys->Length(); + channel_args.args = reinterpret_cast( + calloc(channel_args.num_args, sizeof(grpc_arg))); + /* These are used to keep all strings until then end of the block, then + destroy them */ + std::vector key_strings(keys->Length()); + std::vector value_strings(keys->Length()); + for (unsigned int i = 0; i < channel_args.num_args; i++) { + Handle current_key(keys->Get(i)->ToString()); + Handle current_value(args_hash->Get(current_key)); + key_strings[i] = new NanUtf8String(current_key); + channel_args.args[i].key = **key_strings[i]; + if (current_value->IsInt32()) { + channel_args.args[i].type = GRPC_ARG_INTEGER; + channel_args.args[i].value.integer = current_value->Int32Value(); + } else if (current_value->IsString()) { + channel_args.args[i].type = GRPC_ARG_STRING; + value_strings[i] = new NanUtf8String(current_value); + channel_args.args[i].value.string = **value_strings[i]; + } else { + free(channel_args.args); + return NanThrowTypeError("Arg values must be strings"); + } + } + if (creds == NULL) { + wrapped_channel = grpc_channel_create(**host, &channel_args); + } else { + wrapped_channel = + grpc_secure_channel_create(creds, **host, &channel_args); + } + free(channel_args.args); + } else { + return NanThrowTypeError("Channel expects a string and an object"); + } + Channel *channel = new Channel(wrapped_channel, host); + channel->Wrap(args.This()); + NanReturnValue(args.This()); + } else { + const int argc = 2; + Local argv[argc] = {args[0], args[1]}; + NanReturnValue(constructor->NewInstance(argc, argv)); + } +} + +NAN_METHOD(Channel::Close) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError("close can only be called on Channel objects"); + } + Channel *channel = ObjectWrap::Unwrap(args.This()); + if (channel->wrapped_channel != NULL) { + grpc_channel_destroy(channel->wrapped_channel); + channel->wrapped_channel = NULL; + } + NanReturnUndefined(); +} + +} // namespace node +} // namespace grpc diff --git a/src/node/ext/channel.h b/src/node/ext/channel.h new file mode 100644 index 0000000000..140cbf201a --- /dev/null +++ b/src/node/ext/channel.h @@ -0,0 +1,79 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef NET_GRPC_NODE_CHANNEL_H_ +#define NET_GRPC_NODE_CHANNEL_H_ + +#include +#include +#include "grpc/grpc.h" + +namespace grpc { +namespace node { + +/* Wrapper class for grpc_channel structs */ +class Channel : public ::node::ObjectWrap { + public: + static void Init(v8::Handle exports); + static bool HasInstance(v8::Handle val); + /* This is used to typecheck javascript objects before converting them to + this type */ + static v8::Persistent prototype; + + /* Returns the grpc_channel struct that this object wraps */ + grpc_channel *GetWrappedChannel(); + + /* Return the hostname that this channel connects to */ + char *GetHost(); + + private: + explicit Channel(grpc_channel *channel, NanUtf8String *host); + ~Channel(); + + // Prevent copying + Channel(const Channel &); + Channel &operator=(const Channel &); + + static NAN_METHOD(New); + static NAN_METHOD(Close); + static v8::Persistent constructor; + static v8::Persistent fun_tpl; + + grpc_channel *wrapped_channel; + NanUtf8String *host; +}; + +} // namespace node +} // namespace grpc + +#endif // NET_GRPC_NODE_CHANNEL_H_ diff --git a/src/node/ext/completion_queue_async_worker.cc b/src/node/ext/completion_queue_async_worker.cc new file mode 100644 index 0000000000..8de7db66d5 --- /dev/null +++ b/src/node/ext/completion_queue_async_worker.cc @@ -0,0 +1,89 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include "grpc/grpc.h" +#include "grpc/support/time.h" +#include "completion_queue_async_worker.h" +#include "event.h" +#include "tag.h" + +namespace grpc { +namespace node { + +using v8::Function; +using v8::Handle; +using v8::Object; +using v8::Persistent; +using v8::Value; + +grpc_completion_queue *CompletionQueueAsyncWorker::queue; + +CompletionQueueAsyncWorker::CompletionQueueAsyncWorker() + : NanAsyncWorker(NULL) {} + +CompletionQueueAsyncWorker::~CompletionQueueAsyncWorker() {} + +void CompletionQueueAsyncWorker::Execute() { + result = grpc_completion_queue_next(queue, gpr_inf_future); +} + +grpc_completion_queue *CompletionQueueAsyncWorker::GetQueue() { return queue; } + +void CompletionQueueAsyncWorker::Next() { + NanScope(); + CompletionQueueAsyncWorker *worker = new CompletionQueueAsyncWorker(); + NanAsyncQueueWorker(worker); +} + +void CompletionQueueAsyncWorker::Init(Handle exports) { + NanScope(); + queue = grpc_completion_queue_create(); +} + +void CompletionQueueAsyncWorker::HandleOKCallback() { + NanScope(); + NanCallback event_callback(GetTagHandle(result->tag).As()); + Handle argv[] = {CreateEventObject(result)}; + + DestroyTag(result->tag); + grpc_event_finish(result); + result = NULL; + + event_callback.Call(1, argv); +} + +} // namespace node +} // namespace grpc diff --git a/src/node/ext/completion_queue_async_worker.h b/src/node/ext/completion_queue_async_worker.h new file mode 100644 index 0000000000..2c928b7024 --- /dev/null +++ b/src/node/ext/completion_queue_async_worker.h @@ -0,0 +1,79 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef NET_GRPC_NODE_COMPLETION_QUEUE_ASYNC_WORKER_H_ +#define NET_GRPC_NODE_COMPLETION_QUEUE_ASYNC_WORKER_H_ +#include + +#include "grpc/grpc.h" + +namespace grpc { +namespace node { + +/* A worker that asynchronously calls completion_queue_next, and queues onto the + node event loop a call to the function stored in the event's tag. */ +class CompletionQueueAsyncWorker : public NanAsyncWorker { + public: + CompletionQueueAsyncWorker(); + + ~CompletionQueueAsyncWorker(); + /* Calls completion_queue_next with the provided deadline, and stores the + event if there was one or sets an error message if there was not */ + void Execute(); + + /* Returns the completion queue attached to this class */ + static grpc_completion_queue *GetQueue(); + + /* Convenience function to create a worker with the given arguments and queue + it to run asynchronously */ + static void Next(); + + /* Initialize the CompletionQueueAsyncWorker class */ + static void Init(v8::Handle exports); + + protected: + /* Called when Execute has succeeded (completed without setting an error + message). Calls the saved callback with the event that came from + completion_queue_next */ + void HandleOKCallback(); + + private: + grpc_event *result; + + static grpc_completion_queue *queue; +}; + +} // namespace node +} // namespace grpc + +#endif // NET_GRPC_NODE_COMPLETION_QUEUE_ASYNC_WORKER_H_ diff --git a/src/node/ext/credentials.cc b/src/node/ext/credentials.cc new file mode 100644 index 0000000000..f9cd2fcfe0 --- /dev/null +++ b/src/node/ext/credentials.cc @@ -0,0 +1,205 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include "grpc/grpc.h" +#include "grpc/grpc_security.h" +#include "grpc/support/log.h" +#include "credentials.h" + +namespace grpc { +namespace node { + +using ::node::Buffer; +using v8::Arguments; +using v8::Exception; +using v8::External; +using v8::Function; +using v8::FunctionTemplate; +using v8::Handle; +using v8::HandleScope; +using v8::Integer; +using v8::Local; +using v8::Object; +using v8::ObjectTemplate; +using v8::Persistent; +using v8::Value; + +Persistent Credentials::constructor; +Persistent Credentials::fun_tpl; + +Credentials::Credentials(grpc_credentials *credentials) + : wrapped_credentials(credentials) {} + +Credentials::~Credentials() { + gpr_log(GPR_DEBUG, "Destroying credentials object"); + grpc_credentials_release(wrapped_credentials); +} + +void Credentials::Init(Handle exports) { + NanScope(); + Local tpl = FunctionTemplate::New(New); + tpl->SetClassName(NanNew("Credentials")); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + NanAssignPersistent(fun_tpl, tpl); + NanAssignPersistent(constructor, tpl->GetFunction()); + constructor->Set(NanNew("createDefault"), + FunctionTemplate::New(CreateDefault)->GetFunction()); + constructor->Set(NanNew("createSsl"), + FunctionTemplate::New(CreateSsl)->GetFunction()); + constructor->Set(NanNew("createComposite"), + FunctionTemplate::New(CreateComposite)->GetFunction()); + constructor->Set(NanNew("createGce"), + FunctionTemplate::New(CreateGce)->GetFunction()); + constructor->Set(NanNew("createFake"), + FunctionTemplate::New(CreateFake)->GetFunction()); + constructor->Set(NanNew("createIam"), + FunctionTemplate::New(CreateIam)->GetFunction()); + exports->Set(NanNew("Credentials"), constructor); +} + +bool Credentials::HasInstance(Handle val) { + NanScope(); + return NanHasInstance(fun_tpl, val); +} + +Handle Credentials::WrapStruct(grpc_credentials *credentials) { + NanEscapableScope(); + if (credentials == NULL) { + return NanEscapeScope(NanNull()); + } + const int argc = 1; + Handle argv[argc] = { + External::New(reinterpret_cast(credentials))}; + return NanEscapeScope(constructor->NewInstance(argc, argv)); +} + +grpc_credentials *Credentials::GetWrappedCredentials() { + return wrapped_credentials; +} + +NAN_METHOD(Credentials::New) { + NanScope(); + + if (args.IsConstructCall()) { + if (!args[0]->IsExternal()) { + return NanThrowTypeError( + "Credentials can only be created with the provided functions"); + } + grpc_credentials *creds_value = + reinterpret_cast(External::Unwrap(args[0])); + Credentials *credentials = new Credentials(creds_value); + credentials->Wrap(args.This()); + NanReturnValue(args.This()); + } else { + const int argc = 1; + Local argv[argc] = {args[0]}; + NanReturnValue(constructor->NewInstance(argc, argv)); + } +} + +NAN_METHOD(Credentials::CreateDefault) { + NanScope(); + NanReturnValue(WrapStruct(grpc_default_credentials_create())); +} + +NAN_METHOD(Credentials::CreateSsl) { + NanScope(); + char *root_certs = NULL; + grpc_ssl_pem_key_cert_pair key_cert_pair = {NULL, NULL}; + if (Buffer::HasInstance(args[0])) { + root_certs = Buffer::Data(args[0]); + } else if (!(args[0]->IsNull() || args[0]->IsUndefined())) { + return NanThrowTypeError("createSsl's first argument must be a Buffer"); + } + if (Buffer::HasInstance(args[1])) { + key_cert_pair.private_key = Buffer::Data(args[1]); + } else if (!(args[1]->IsNull() || args[1]->IsUndefined())) { + return NanThrowTypeError( + "createSSl's second argument must be a Buffer if provided"); + } + if (Buffer::HasInstance(args[2])) { + key_cert_pair.cert_chain = Buffer::Data(args[2]); + } else if (!(args[2]->IsNull() || args[2]->IsUndefined())) { + return NanThrowTypeError( + "createSSl's third argument must be a Buffer if provided"); + } + + NanReturnValue(WrapStruct(grpc_ssl_credentials_create( + root_certs, + key_cert_pair.private_key == NULL ? NULL : &key_cert_pair))); +} + +NAN_METHOD(Credentials::CreateComposite) { + NanScope(); + if (!HasInstance(args[0])) { + return NanThrowTypeError( + "createComposite's first argument must be a Credentials object"); + } + if (!HasInstance(args[1])) { + return NanThrowTypeError( + "createComposite's second argument must be a Credentials object"); + } + Credentials *creds1 = ObjectWrap::Unwrap(args[0]->ToObject()); + Credentials *creds2 = ObjectWrap::Unwrap(args[1]->ToObject()); + NanReturnValue(WrapStruct(grpc_composite_credentials_create( + creds1->wrapped_credentials, creds2->wrapped_credentials))); +} + +NAN_METHOD(Credentials::CreateGce) { + NanScope(); + 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()) { + return NanThrowTypeError("createIam's first argument must be a string"); + } + if (!args[1]->IsString()) { + return NanThrowTypeError("createIam's second argument must be a string"); + } + NanUtf8String auth_token(args[0]); + NanUtf8String auth_selector(args[1]); + NanReturnValue( + WrapStruct(grpc_iam_credentials_create(*auth_token, *auth_selector))); +} + +} // namespace node +} // namespace grpc diff --git a/src/node/ext/credentials.h b/src/node/ext/credentials.h new file mode 100644 index 0000000000..981e5a99bc --- /dev/null +++ b/src/node/ext/credentials.h @@ -0,0 +1,81 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef NET_GRPC_NODE_CREDENTIALS_H_ +#define NET_GRPC_NODE_CREDENTIALS_H_ + +#include +#include +#include "grpc/grpc.h" +#include "grpc/grpc_security.h" + +namespace grpc { +namespace node { + +/* Wrapper class for grpc_credentials structs */ +class Credentials : public ::node::ObjectWrap { + public: + static void Init(v8::Handle exports); + static bool HasInstance(v8::Handle val); + /* Wrap a grpc_credentials struct in a javascript object */ + static v8::Handle WrapStruct(grpc_credentials *credentials); + + /* Returns the grpc_credentials struct that this object wraps */ + grpc_credentials *GetWrappedCredentials(); + + private: + explicit Credentials(grpc_credentials *credentials); + ~Credentials(); + + // Prevent copying + Credentials(const Credentials &); + Credentials &operator=(const Credentials &); + + static NAN_METHOD(New); + static NAN_METHOD(CreateDefault); + static NAN_METHOD(CreateSsl); + static NAN_METHOD(CreateComposite); + static NAN_METHOD(CreateGce); + static NAN_METHOD(CreateFake); + static NAN_METHOD(CreateIam); + static v8::Persistent constructor; + // Used for typechecking instances of this javascript class + static v8::Persistent fun_tpl; + + grpc_credentials *wrapped_credentials; +}; + +} // namespace node +} // namespace grpc + +#endif // NET_GRPC_NODE_CREDENTIALS_H_ diff --git a/src/node/ext/event.cc b/src/node/ext/event.cc new file mode 100644 index 0000000000..2ca38b7448 --- /dev/null +++ b/src/node/ext/event.cc @@ -0,0 +1,164 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include "grpc/grpc.h" +#include "byte_buffer.h" +#include "call.h" +#include "event.h" +#include "tag.h" +#include "timeval.h" + +namespace grpc { +namespace node { + +using v8::Array; +using v8::Date; +using v8::Handle; +using v8::HandleScope; +using v8::Number; +using v8::Object; +using v8::Persistent; +using v8::String; +using v8::Value; + +Handle GetEventData(grpc_event *event) { + NanEscapableScope(); + size_t count; + grpc_metadata *items; + Handle metadata; + Handle status; + Handle rpc_new; + switch (event->type) { + case GRPC_READ: + return NanEscapeScope(ByteBufferToBuffer(event->data.read)); + case GRPC_INVOKE_ACCEPTED: + return NanEscapeScope(NanNew(event->data.invoke_accepted)); + case GRPC_WRITE_ACCEPTED: + return NanEscapeScope(NanNew(event->data.write_accepted)); + case GRPC_FINISH_ACCEPTED: + return NanEscapeScope(NanNew(event->data.finish_accepted)); + case GRPC_CLIENT_METADATA_READ: + count = event->data.client_metadata_read.count; + items = event->data.client_metadata_read.elements; + metadata = NanNew(static_cast(count)); + for (unsigned int i = 0; i < count; i++) { + Handle item_obj = NanNew(); + item_obj->Set(NanNew("key"), + NanNew(items[i].key)); + item_obj->Set( + NanNew("value"), + NanNew(items[i].value, + static_cast(items[i].value_length))); + metadata->Set(i, item_obj); + } + return NanEscapeScope(metadata); + case GRPC_FINISHED: + status = NanNew(); + status->Set(NanNew("code"), NanNew(event->data.finished.status)); + if (event->data.finished.details != NULL) { + status->Set(NanNew("details"), + String::New(event->data.finished.details)); + } + count = event->data.finished.metadata_count; + items = event->data.finished.metadata_elements; + metadata = NanNew(static_cast(count)); + for (unsigned int i = 0; i < count; i++) { + Handle item_obj = NanNew(); + item_obj->Set(NanNew("key"), + NanNew(items[i].key)); + item_obj->Set( + NanNew("value"), + NanNew(items[i].value, + static_cast(items[i].value_length))); + metadata->Set(i, item_obj); + } + status->Set(NanNew("metadata"), metadata); + return NanEscapeScope(status); + case GRPC_SERVER_RPC_NEW: + rpc_new = NanNew(); + if (event->data.server_rpc_new.method == NULL) { + return NanEscapeScope(NanNull()); + } + rpc_new->Set( + NanNew("method"), + NanNew(event->data.server_rpc_new.method)); + rpc_new->Set( + NanNew("host"), + NanNew(event->data.server_rpc_new.host)); + rpc_new->Set(NanNew("absolute_deadline"), + NanNew(TimespecToMilliseconds( + event->data.server_rpc_new.deadline))); + count = event->data.server_rpc_new.metadata_count; + items = event->data.server_rpc_new.metadata_elements; + metadata = NanNew(static_cast(count)); + for (unsigned int i = 0; i < count; i++) { + Handle item_obj = Object::New(); + item_obj->Set(NanNew("key"), + NanNew(items[i].key)); + item_obj->Set( + NanNew("value"), + NanNew(items[i].value, + static_cast(items[i].value_length))); + metadata->Set(i, item_obj); + } + rpc_new->Set(NanNew("metadata"), metadata); + return NanEscapeScope(rpc_new); + default: + return NanEscapeScope(NanNull()); + } +} + +Handle CreateEventObject(grpc_event *event) { + NanEscapableScope(); + if (event == NULL) { + return NanEscapeScope(NanNull()); + } + Handle event_obj = NanNew(); + Handle call; + if (TagHasCall(event->tag)) { + call = TagGetCall(event->tag); + } else { + call = Call::WrapStruct(event->call); + } + event_obj->Set(NanNew("call"), call); + event_obj->Set(NanNew("type"), + NanNew(event->type)); + event_obj->Set(NanNew("data"), GetEventData(event)); + + return NanEscapeScope(event_obj); +} + +} // namespace node +} // namespace grpc diff --git a/src/node/ext/event.h b/src/node/ext/event.h new file mode 100644 index 0000000000..e06d8f0168 --- /dev/null +++ b/src/node/ext/event.h @@ -0,0 +1,48 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef NET_GRPC_NODE_EVENT_H_ +#define NET_GRPC_NODE_EVENT_H_ + +#include +#include "grpc/grpc.h" + +namespace grpc { +namespace node { + +v8::Handle CreateEventObject(grpc_event *event); + +} // namespace node +} // namespace grpc + +#endif // NET_GRPC_NODE_EVENT_H_ diff --git a/src/node/ext/node_grpc.cc b/src/node/ext/node_grpc.cc new file mode 100644 index 0000000000..bc1dfaf899 --- /dev/null +++ b/src/node/ext/node_grpc.cc @@ -0,0 +1,180 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include "grpc/grpc.h" + +#include "call.h" +#include "channel.h" +#include "event.h" +#include "server.h" +#include "completion_queue_async_worker.h" +#include "credentials.h" +#include "server_credentials.h" + +using v8::Handle; +using v8::Value; +using v8::Object; +using v8::Uint32; +using v8::String; + +void InitStatusConstants(Handle exports) { + NanScope(); + Handle status = Object::New(); + exports->Set(NanNew("status"), status); + Handle OK(NanNew(GRPC_STATUS_OK)); + status->Set(NanNew("OK"), OK); + Handle CANCELLED(NanNew(GRPC_STATUS_CANCELLED)); + status->Set(NanNew("CANCELLED"), CANCELLED); + Handle UNKNOWN(NanNew(GRPC_STATUS_UNKNOWN)); + status->Set(NanNew("UNKNOWN"), UNKNOWN); + Handle INVALID_ARGUMENT( + NanNew(GRPC_STATUS_INVALID_ARGUMENT)); + status->Set(NanNew("INVALID_ARGUMENT"), INVALID_ARGUMENT); + Handle DEADLINE_EXCEEDED( + NanNew(GRPC_STATUS_DEADLINE_EXCEEDED)); + status->Set(NanNew("DEADLINE_EXCEEDED"), DEADLINE_EXCEEDED); + Handle NOT_FOUND(NanNew(GRPC_STATUS_NOT_FOUND)); + status->Set(NanNew("NOT_FOUND"), NOT_FOUND); + Handle ALREADY_EXISTS( + NanNew(GRPC_STATUS_ALREADY_EXISTS)); + status->Set(NanNew("ALREADY_EXISTS"), ALREADY_EXISTS); + Handle PERMISSION_DENIED( + NanNew(GRPC_STATUS_PERMISSION_DENIED)); + status->Set(NanNew("PERMISSION_DENIED"), PERMISSION_DENIED); + Handle UNAUTHENTICATED( + NanNew(GRPC_STATUS_UNAUTHENTICATED)); + status->Set(NanNew("UNAUTHENTICATED"), UNAUTHENTICATED); + Handle RESOURCE_EXHAUSTED( + NanNew(GRPC_STATUS_RESOURCE_EXHAUSTED)); + status->Set(NanNew("RESOURCE_EXHAUSTED"), RESOURCE_EXHAUSTED); + Handle FAILED_PRECONDITION( + NanNew(GRPC_STATUS_FAILED_PRECONDITION)); + status->Set(NanNew("FAILED_PRECONDITION"), FAILED_PRECONDITION); + Handle ABORTED(NanNew(GRPC_STATUS_ABORTED)); + status->Set(NanNew("ABORTED"), ABORTED); + Handle OUT_OF_RANGE( + NanNew(GRPC_STATUS_OUT_OF_RANGE)); + status->Set(NanNew("OUT_OF_RANGE"), OUT_OF_RANGE); + Handle UNIMPLEMENTED( + NanNew(GRPC_STATUS_UNIMPLEMENTED)); + status->Set(NanNew("UNIMPLEMENTED"), UNIMPLEMENTED); + Handle INTERNAL(NanNew(GRPC_STATUS_INTERNAL)); + status->Set(NanNew("INTERNAL"), INTERNAL); + Handle UNAVAILABLE(NanNew(GRPC_STATUS_UNAVAILABLE)); + status->Set(NanNew("UNAVAILABLE"), UNAVAILABLE); + Handle DATA_LOSS(NanNew(GRPC_STATUS_DATA_LOSS)); + status->Set(NanNew("DATA_LOSS"), DATA_LOSS); +} + +void InitCallErrorConstants(Handle exports) { + NanScope(); + Handle call_error = Object::New(); + exports->Set(NanNew("callError"), call_error); + Handle OK(NanNew(GRPC_CALL_OK)); + call_error->Set(NanNew("OK"), OK); + Handle ERROR(NanNew(GRPC_CALL_ERROR)); + call_error->Set(NanNew("ERROR"), ERROR); + Handle NOT_ON_SERVER( + NanNew(GRPC_CALL_ERROR_NOT_ON_SERVER)); + call_error->Set(NanNew("NOT_ON_SERVER"), NOT_ON_SERVER); + Handle NOT_ON_CLIENT( + NanNew(GRPC_CALL_ERROR_NOT_ON_CLIENT)); + call_error->Set(NanNew("NOT_ON_CLIENT"), NOT_ON_CLIENT); + Handle ALREADY_INVOKED( + NanNew(GRPC_CALL_ERROR_ALREADY_INVOKED)); + call_error->Set(NanNew("ALREADY_INVOKED"), ALREADY_INVOKED); + Handle NOT_INVOKED( + NanNew(GRPC_CALL_ERROR_NOT_INVOKED)); + call_error->Set(NanNew("NOT_INVOKED"), NOT_INVOKED); + Handle ALREADY_FINISHED( + NanNew(GRPC_CALL_ERROR_ALREADY_FINISHED)); + call_error->Set(NanNew("ALREADY_FINISHED"), ALREADY_FINISHED); + Handle TOO_MANY_OPERATIONS( + NanNew(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS)); + call_error->Set(NanNew("TOO_MANY_OPERATIONS"), TOO_MANY_OPERATIONS); + Handle INVALID_FLAGS( + NanNew(GRPC_CALL_ERROR_INVALID_FLAGS)); + call_error->Set(NanNew("INVALID_FLAGS"), INVALID_FLAGS); +} + +void InitOpErrorConstants(Handle exports) { + NanScope(); + Handle op_error = Object::New(); + exports->Set(NanNew("opError"), op_error); + Handle OK(NanNew(GRPC_OP_OK)); + op_error->Set(NanNew("OK"), OK); + Handle ERROR(NanNew(GRPC_OP_ERROR)); + op_error->Set(NanNew("ERROR"), ERROR); +} + +void InitCompletionTypeConstants(Handle exports) { + NanScope(); + Handle completion_type = Object::New(); + exports->Set(NanNew("completionType"), completion_type); + Handle QUEUE_SHUTDOWN(NanNew(GRPC_QUEUE_SHUTDOWN)); + completion_type->Set(NanNew("QUEUE_SHUTDOWN"), QUEUE_SHUTDOWN); + Handle READ(NanNew(GRPC_READ)); + completion_type->Set(NanNew("READ"), READ); + Handle WRITE_ACCEPTED(NanNew(GRPC_WRITE_ACCEPTED)); + completion_type->Set(NanNew("WRITE_ACCEPTED"), WRITE_ACCEPTED); + Handle FINISH_ACCEPTED(NanNew(GRPC_FINISH_ACCEPTED)); + completion_type->Set(NanNew("FINISH_ACCEPTED"), FINISH_ACCEPTED); + Handle CLIENT_METADATA_READ( + NanNew(GRPC_CLIENT_METADATA_READ)); + completion_type->Set(NanNew("CLIENT_METADATA_READ"), CLIENT_METADATA_READ); + Handle FINISHED(NanNew(GRPC_FINISHED)); + completion_type->Set(NanNew("FINISHED"), FINISHED); + Handle SERVER_RPC_NEW(NanNew(GRPC_SERVER_RPC_NEW)); + completion_type->Set(NanNew("SERVER_RPC_NEW"), SERVER_RPC_NEW); +} + +void init(Handle exports) { + NanScope(); + grpc_init(); + InitStatusConstants(exports); + InitCallErrorConstants(exports); + InitOpErrorConstants(exports); + InitCompletionTypeConstants(exports); + + grpc::node::Call::Init(exports); + grpc::node::Channel::Init(exports); + grpc::node::Server::Init(exports); + grpc::node::CompletionQueueAsyncWorker::Init(exports); + grpc::node::Credentials::Init(exports); + grpc::node::ServerCredentials::Init(exports); +} + +NODE_MODULE(grpc, init) diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc new file mode 100644 index 0000000000..b102775d33 --- /dev/null +++ b/src/node/ext/server.cc @@ -0,0 +1,236 @@ +/* + * + * Copyright 2014, 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 "server.h" + +#include +#include + +#include + +#include +#include "grpc/grpc.h" +#include "grpc/grpc_security.h" +#include "call.h" +#include "completion_queue_async_worker.h" +#include "tag.h" +#include "server_credentials.h" + +namespace grpc { +namespace node { + +using v8::Arguments; +using v8::Array; +using v8::Boolean; +using v8::Exception; +using v8::Function; +using v8::FunctionTemplate; +using v8::Handle; +using v8::HandleScope; +using v8::Local; +using v8::Number; +using v8::Object; +using v8::Persistent; +using v8::String; +using v8::Value; + +Persistent Server::constructor; +Persistent Server::fun_tpl; + +Server::Server(grpc_server *server) : wrapped_server(server) {} + +Server::~Server() { grpc_server_destroy(wrapped_server); } + +void Server::Init(Handle exports) { + NanScope(); + Local tpl = FunctionTemplate::New(New); + tpl->SetClassName(String::NewSymbol("Server")); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + NanSetPrototypeTemplate(tpl, "requestCall", + FunctionTemplate::New(RequestCall)->GetFunction()); + + NanSetPrototypeTemplate(tpl, "addHttp2Port", + FunctionTemplate::New(AddHttp2Port)->GetFunction()); + + NanSetPrototypeTemplate( + tpl, "addSecureHttp2Port", + FunctionTemplate::New(AddSecureHttp2Port)->GetFunction()); + + NanSetPrototypeTemplate(tpl, "start", + FunctionTemplate::New(Start)->GetFunction()); + + NanSetPrototypeTemplate(tpl, "shutdown", + FunctionTemplate::New(Shutdown)->GetFunction()); + + NanAssignPersistent(fun_tpl, tpl); + NanAssignPersistent(constructor, tpl->GetFunction()); + exports->Set(String::NewSymbol("Server"), constructor); +} + +bool Server::HasInstance(Handle val) { + return NanHasInstance(fun_tpl, val); +} + +NAN_METHOD(Server::New) { + NanScope(); + + /* If this is not a constructor call, make a constructor call and return + the result */ + if (!args.IsConstructCall()) { + const int argc = 1; + Local argv[argc] = {args[0]}; + NanReturnValue(constructor->NewInstance(argc, argv)); + } + grpc_server *wrapped_server; + grpc_completion_queue *queue = CompletionQueueAsyncWorker::GetQueue(); + if (args[0]->IsUndefined()) { + wrapped_server = grpc_server_create(queue, NULL); + } else if (args[0]->IsObject()) { + grpc_server_credentials *creds = NULL; + Handle args_hash(args[0]->ToObject()->Clone()); + if (args_hash->HasOwnProperty(NanNew("credentials"))) { + Handle creds_value = args_hash->Get(NanNew("credentials")); + if (!ServerCredentials::HasInstance(creds_value)) { + return NanThrowTypeError( + "credentials arg must be a ServerCredentials object"); + } + ServerCredentials *creds_object = + ObjectWrap::Unwrap(creds_value->ToObject()); + creds = creds_object->GetWrappedServerCredentials(); + args_hash->Delete(NanNew("credentials")); + } + Handle keys(args_hash->GetOwnPropertyNames()); + grpc_channel_args channel_args; + channel_args.num_args = keys->Length(); + channel_args.args = reinterpret_cast( + calloc(channel_args.num_args, sizeof(grpc_arg))); + /* These are used to keep all strings until then end of the block, then + destroy them */ + std::vector key_strings(keys->Length()); + std::vector value_strings(keys->Length()); + for (unsigned int i = 0; i < channel_args.num_args; i++) { + Handle current_key(keys->Get(i)->ToString()); + Handle current_value(args_hash->Get(current_key)); + key_strings[i] = new NanUtf8String(current_key); + channel_args.args[i].key = **key_strings[i]; + if (current_value->IsInt32()) { + channel_args.args[i].type = GRPC_ARG_INTEGER; + channel_args.args[i].value.integer = current_value->Int32Value(); + } else if (current_value->IsString()) { + channel_args.args[i].type = GRPC_ARG_STRING; + value_strings[i] = new NanUtf8String(current_value); + channel_args.args[i].value.string = **value_strings[i]; + } else { + free(channel_args.args); + return NanThrowTypeError("Arg values must be strings"); + } + } + if (creds == NULL) { + wrapped_server = grpc_server_create(queue, &channel_args); + } else { + wrapped_server = grpc_secure_server_create(creds, queue, &channel_args); + } + free(channel_args.args); + } else { + return NanThrowTypeError("Server expects an object"); + } + Server *server = new Server(wrapped_server); + server->Wrap(args.This()); + NanReturnValue(args.This()); +} + +NAN_METHOD(Server::RequestCall) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError("requestCall can only be called on a Server"); + } + Server *server = ObjectWrap::Unwrap(args.This()); + grpc_call_error error = grpc_server_request_call( + server->wrapped_server, CreateTag(args[0], NanNull())); + if (error == GRPC_CALL_OK) { + CompletionQueueAsyncWorker::Next(); + } else { + return NanThrowError("requestCall failed", error); + } + NanReturnUndefined(); +} + +NAN_METHOD(Server::AddHttp2Port) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError("addHttp2Port can only be called on a Server"); + } + if (!args[0]->IsString()) { + return NanThrowTypeError("addHttp2Port's argument must be a String"); + } + Server *server = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(grpc_server_add_http2_port( + server->wrapped_server, *NanUtf8String(args[0])))); +} + +NAN_METHOD(Server::AddSecureHttp2Port) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError( + "addSecureHttp2Port can only be called on a Server"); + } + if (!args[0]->IsString()) { + return NanThrowTypeError("addSecureHttp2Port's argument must be a String"); + } + Server *server = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(grpc_server_add_secure_http2_port( + server->wrapped_server, *NanUtf8String(args[0])))); +} + +NAN_METHOD(Server::Start) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError("start can only be called on a Server"); + } + Server *server = ObjectWrap::Unwrap(args.This()); + grpc_server_start(server->wrapped_server); + NanReturnUndefined(); +} + +NAN_METHOD(Server::Shutdown) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError("shutdown can only be called on a Server"); + } + Server *server = ObjectWrap::Unwrap(args.This()); + grpc_server_shutdown(server->wrapped_server); + NanReturnUndefined(); +} + +} // namespace node +} // namespace grpc diff --git a/src/node/ext/server.h b/src/node/ext/server.h new file mode 100644 index 0000000000..d50f1fb6c5 --- /dev/null +++ b/src/node/ext/server.h @@ -0,0 +1,79 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef NET_GRPC_NODE_SERVER_H_ +#define NET_GRPC_NODE_SERVER_H_ + +#include +#include +#include "grpc/grpc.h" + +namespace grpc { +namespace node { + +/* Wraps grpc_server as a JavaScript object. Provides a constructor + and wrapper methods for grpc_server_create, grpc_server_request_call, + grpc_server_add_http2_port, and grpc_server_start. */ +class Server : public ::node::ObjectWrap { + public: + /* Initializes the Server class and exposes the constructor and + wrapper methods to JavaScript */ + static void Init(v8::Handle exports); + /* Tests whether the given value was constructed by this class's + JavaScript constructor */ + static bool HasInstance(v8::Handle val); + + private: + explicit Server(grpc_server *server); + ~Server(); + + // Prevent copying + Server(const Server &); + Server &operator=(const Server &); + + static NAN_METHOD(New); + static NAN_METHOD(RequestCall); + static NAN_METHOD(AddHttp2Port); + static NAN_METHOD(AddSecureHttp2Port); + static NAN_METHOD(Start); + static NAN_METHOD(Shutdown); + static v8::Persistent constructor; + static v8::Persistent fun_tpl; + + grpc_server *wrapped_server; +}; + +} // namespace node +} // namespace grpc + +#endif // NET_GRPC_NODE_SERVER_H_ diff --git a/src/node/ext/server_credentials.cc b/src/node/ext/server_credentials.cc new file mode 100644 index 0000000000..393f3a6305 --- /dev/null +++ b/src/node/ext/server_credentials.cc @@ -0,0 +1,155 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include "grpc/grpc.h" +#include "grpc/grpc_security.h" +#include "grpc/support/log.h" +#include "server_credentials.h" + +namespace grpc { +namespace node { + +using ::node::Buffer; +using v8::Arguments; +using v8::Exception; +using v8::External; +using v8::Function; +using v8::FunctionTemplate; +using v8::Handle; +using v8::HandleScope; +using v8::Integer; +using v8::Local; +using v8::Object; +using v8::ObjectTemplate; +using v8::Persistent; +using v8::Value; + +Persistent ServerCredentials::constructor; +Persistent ServerCredentials::fun_tpl; + +ServerCredentials::ServerCredentials(grpc_server_credentials *credentials) + : wrapped_credentials(credentials) {} + +ServerCredentials::~ServerCredentials() { + gpr_log(GPR_DEBUG, "Destroying server credentials object"); + grpc_server_credentials_release(wrapped_credentials); +} + +void ServerCredentials::Init(Handle exports) { + NanScope(); + Local tpl = FunctionTemplate::New(New); + tpl->SetClassName(NanNew("ServerCredentials")); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + NanAssignPersistent(fun_tpl, tpl); + NanAssignPersistent(constructor, tpl->GetFunction()); + constructor->Set(NanNew("createSsl"), + FunctionTemplate::New(CreateSsl)->GetFunction()); + constructor->Set(NanNew("createFake"), + FunctionTemplate::New(CreateFake)->GetFunction()); + exports->Set(NanNew("ServerCredentials"), constructor); +} + +bool ServerCredentials::HasInstance(Handle val) { + NanScope(); + return NanHasInstance(fun_tpl, val); +} + +Handle ServerCredentials::WrapStruct( + grpc_server_credentials *credentials) { + NanEscapableScope(); + if (credentials == NULL) { + return NanEscapeScope(NanNull()); + } + const int argc = 1; + Handle argv[argc] = { + External::New(reinterpret_cast(credentials))}; + return NanEscapeScope(constructor->NewInstance(argc, argv)); +} + +grpc_server_credentials *ServerCredentials::GetWrappedServerCredentials() { + return wrapped_credentials; +} + +NAN_METHOD(ServerCredentials::New) { + NanScope(); + + if (args.IsConstructCall()) { + if (!args[0]->IsExternal()) { + return NanThrowTypeError( + "ServerCredentials can only be created with the provide functions"); + } + grpc_server_credentials *creds_value = + reinterpret_cast(External::Unwrap(args[0])); + ServerCredentials *credentials = new ServerCredentials(creds_value); + credentials->Wrap(args.This()); + NanReturnValue(args.This()); + } else { + const int argc = 1; + Local argv[argc] = {args[0]}; + NanReturnValue(constructor->NewInstance(argc, argv)); + } +} + +NAN_METHOD(ServerCredentials::CreateSsl) { + // TODO: have the node API support multiple key/cert pairs. + NanScope(); + char *root_certs = NULL; + grpc_ssl_pem_key_cert_pair key_cert_pair; + if (Buffer::HasInstance(args[0])) { + root_certs = Buffer::Data(args[0]); + } else if (!(args[0]->IsNull() || args[0]->IsUndefined())) { + return NanThrowTypeError( + "createSSl's first argument must be a Buffer if provided"); + } + if (!Buffer::HasInstance(args[1])) { + return NanThrowTypeError("createSsl's second argument must be a Buffer"); + } + key_cert_pair.private_key = Buffer::Data(args[1]); + if (!Buffer::HasInstance(args[2])) { + return NanThrowTypeError("createSsl's third argument must be a Buffer"); + } + key_cert_pair.cert_chain = Buffer::Data(args[2]); + 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())); +} + +} // namespace node +} // namespace grpc diff --git a/src/node/ext/server_credentials.h b/src/node/ext/server_credentials.h new file mode 100644 index 0000000000..8baae3f185 --- /dev/null +++ b/src/node/ext/server_credentials.h @@ -0,0 +1,77 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef NET_GRPC_NODE_SERVER_CREDENTIALS_H_ +#define NET_GRPC_NODE_SERVER_CREDENTIALS_H_ + +#include +#include +#include "grpc/grpc.h" +#include "grpc/grpc_security.h" + +namespace grpc { +namespace node { + +/* Wrapper class for grpc_server_credentials structs */ +class ServerCredentials : public ::node::ObjectWrap { + public: + static void Init(v8::Handle exports); + static bool HasInstance(v8::Handle val); + /* Wrap a grpc_server_credentials struct in a javascript object */ + static v8::Handle WrapStruct(grpc_server_credentials *credentials); + + /* Returns the grpc_server_credentials struct that this object wraps */ + grpc_server_credentials *GetWrappedServerCredentials(); + + private: + explicit ServerCredentials(grpc_server_credentials *credentials); + ~ServerCredentials(); + + // Prevent copying + ServerCredentials(const ServerCredentials &); + ServerCredentials &operator=(const ServerCredentials &); + + static NAN_METHOD(New); + static NAN_METHOD(CreateSsl); + static NAN_METHOD(CreateFake); + static v8::Persistent constructor; + // Used for typechecking instances of this javascript class + static v8::Persistent fun_tpl; + + grpc_server_credentials *wrapped_credentials; +}; + +} // namespace node +} // namespace grpc + +#endif // NET_GRPC_NODE_SERVER_CREDENTIALS_H_ diff --git a/src/node/ext/tag.cc b/src/node/ext/tag.cc new file mode 100644 index 0000000000..dc8e523e12 --- /dev/null +++ b/src/node/ext/tag.cc @@ -0,0 +1,101 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include "tag.h" + +namespace grpc { +namespace node { + +using v8::Handle; +using v8::HandleScope; +using v8::Persistent; +using v8::Value; + +struct tag { + tag(Persistent *tag, Persistent *call) + : persist_tag(tag), persist_call(call) {} + + ~tag() { + persist_tag->Dispose(); + if (persist_call != NULL) { + persist_call->Dispose(); + } + } + Persistent *persist_tag; + Persistent *persist_call; +}; + +void *CreateTag(Handle tag, Handle call) { + NanScope(); + Persistent *persist_tag = new Persistent(); + NanAssignPersistent(*persist_tag, tag); + Persistent *persist_call; + if (call->IsNull() || call->IsUndefined()) { + persist_call = NULL; + } else { + persist_call = new Persistent(); + NanAssignPersistent(*persist_call, call); + } + struct tag *tag_struct = new struct tag(persist_tag, persist_call); + return reinterpret_cast(tag_struct); +} + +Handle GetTagHandle(void *tag) { + NanEscapableScope(); + struct tag *tag_struct = reinterpret_cast(tag); + Handle tag_value = NanNew(*tag_struct->persist_tag); + return NanEscapeScope(tag_value); +} + +bool TagHasCall(void *tag) { + struct tag *tag_struct = reinterpret_cast(tag); + return tag_struct->persist_call != NULL; +} + +Handle TagGetCall(void *tag) { + NanEscapableScope(); + struct tag *tag_struct = reinterpret_cast(tag); + if (tag_struct->persist_call == NULL) { + return NanEscapeScope(NanNull()); + } + Handle call_value = NanNew(*tag_struct->persist_call); + return NanEscapeScope(call_value); +} + +void DestroyTag(void *tag) { delete reinterpret_cast(tag); } + +} // namespace node +} // namespace grpc diff --git a/src/node/ext/tag.h b/src/node/ext/tag.h new file mode 100644 index 0000000000..bdb09252d9 --- /dev/null +++ b/src/node/ext/tag.h @@ -0,0 +1,59 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef NET_GRPC_NODE_TAG_H_ +#define NET_GRPC_NODE_TAG_H_ + +#include + +namespace grpc { +namespace node { + +/* Create a void* tag that can be passed to various grpc_call functions from + a javascript value and the javascript wrapper for the call. The call can be + null. */ +void *CreateTag(v8::Handle tag, v8::Handle call); +/* Return the javascript value stored in the tag */ +v8::Handle GetTagHandle(void *tag); +/* Returns true if the call was set (non-null) when the tag was created */ +bool TagHasCall(void *tag); +/* Returns the javascript wrapper for the call associated with this tag */ +v8::Handle TagGetCall(void *call); +/* Destroy the tag and all resources it is holding. It is illegal to call any + of these other functions on a tag after it has been destroyed. */ +void DestroyTag(void *tag); + +} // namespace node +} // namespace grpc + +#endif // NET_GRPC_NODE_TAG_H_ diff --git a/src/node/ext/timeval.cc b/src/node/ext/timeval.cc new file mode 100644 index 0000000000..687e33576b --- /dev/null +++ b/src/node/ext/timeval.cc @@ -0,0 +1,66 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include "grpc/grpc.h" +#include "grpc/support/time.h" +#include "timeval.h" + +namespace grpc { +namespace node { + +gpr_timespec MillisecondsToTimespec(double millis) { + if (millis == std::numeric_limits::infinity()) { + return gpr_inf_future; + } else if (millis == -std::numeric_limits::infinity()) { + return gpr_inf_past; + } else { + return gpr_time_from_micros(static_cast(millis * 1000)); + } +} + +double TimespecToMilliseconds(gpr_timespec timespec) { + if (gpr_time_cmp(timespec, gpr_inf_future) == 0) { + return std::numeric_limits::infinity(); + } else if (gpr_time_cmp(timespec, gpr_inf_past) == 0) { + return -std::numeric_limits::infinity(); + } else { + struct timeval time = gpr_timeval_from_timespec(timespec); + return (static_cast(time.tv_sec) * 1000 + + static_cast(time.tv_usec) / 1000); + } +} + +} // namespace node +} // namespace grpc diff --git a/src/node/ext/timeval.h b/src/node/ext/timeval.h new file mode 100644 index 0000000000..1fb0f2c690 --- /dev/null +++ b/src/node/ext/timeval.h @@ -0,0 +1,48 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef NET_GRPC_NODE_TIMEVAL_H_ +#define NET_GRPC_NODE_TIMEVAL_H_ + +#include "grpc/support/time.h" + +namespace grpc { +namespace node { + +double TimespecToMilliseconds(gpr_timespec time); +gpr_timespec MillisecondsToTimespec(double millis); + +} // namespace node +} // namespace grpc + +#endif // NET_GRPC_NODE_TIMEVAL_H_ diff --git a/src/node/index.js b/src/node/index.js new file mode 100644 index 0000000000..751c3525d3 --- /dev/null +++ b/src/node/index.js @@ -0,0 +1,108 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +var _ = require('underscore'); + +var ProtoBuf = require('protobufjs'); + +var surface_client = require('./surface_client.js'); + +var surface_server = require('./surface_server.js'); + +var grpc = require('bindings')('grpc'); + +/** + * Load a gRPC object from an existing ProtoBuf.Reflect object. + * @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load. + * @return {Object} The resulting gRPC object + */ +function loadObject(value) { + var result = {}; + if (value.className === 'Namespace') { + _.each(value.children, function(child) { + result[child.name] = loadObject(child); + }); + return result; + } else if (value.className === 'Service') { + return surface_client.makeClientConstructor(value); + } else if (value.className === 'Message' || value.className === 'Enum') { + return value.build(); + } else { + return value; + } +} + +/** + * Load a gRPC object from a .proto file. + * @param {string} filename The file to load + * @return {Object} The resulting gRPC object + */ +function load(filename) { + var builder = ProtoBuf.loadProtoFile(filename); + + return loadObject(builder.ns); +} + +/** + * See docs for loadObject + */ +exports.loadObject = loadObject; + +/** + * See docs for load + */ +exports.load = load; + +/** + * See docs for surface_server.makeServerConstructor + */ +exports.buildServer = surface_server.makeServerConstructor; + +/** + * Status name to code number mapping + */ +exports.status = grpc.status; +/** + * Call error name to code number mapping + */ +exports.callError = grpc.callError; + +/** + * Credentials factories + */ +exports.Credentials = grpc.Credentials; + +/** + * ServerCredentials factories + */ +exports.ServerCredentials = grpc.ServerCredentials; diff --git a/src/node/main.js b/src/node/main.js deleted file mode 100644 index 751c3525d3..0000000000 --- a/src/node/main.js +++ /dev/null @@ -1,108 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -var _ = require('underscore'); - -var ProtoBuf = require('protobufjs'); - -var surface_client = require('./surface_client.js'); - -var surface_server = require('./surface_server.js'); - -var grpc = require('bindings')('grpc'); - -/** - * Load a gRPC object from an existing ProtoBuf.Reflect object. - * @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load. - * @return {Object} The resulting gRPC object - */ -function loadObject(value) { - var result = {}; - if (value.className === 'Namespace') { - _.each(value.children, function(child) { - result[child.name] = loadObject(child); - }); - return result; - } else if (value.className === 'Service') { - return surface_client.makeClientConstructor(value); - } else if (value.className === 'Message' || value.className === 'Enum') { - return value.build(); - } else { - return value; - } -} - -/** - * Load a gRPC object from a .proto file. - * @param {string} filename The file to load - * @return {Object} The resulting gRPC object - */ -function load(filename) { - var builder = ProtoBuf.loadProtoFile(filename); - - return loadObject(builder.ns); -} - -/** - * See docs for loadObject - */ -exports.loadObject = loadObject; - -/** - * See docs for load - */ -exports.load = load; - -/** - * See docs for surface_server.makeServerConstructor - */ -exports.buildServer = surface_server.makeServerConstructor; - -/** - * Status name to code number mapping - */ -exports.status = grpc.status; -/** - * Call error name to code number mapping - */ -exports.callError = grpc.callError; - -/** - * Credentials factories - */ -exports.Credentials = grpc.Credentials; - -/** - * ServerCredentials factories - */ -exports.ServerCredentials = grpc.ServerCredentials; diff --git a/src/node/node_grpc.cc b/src/node/node_grpc.cc deleted file mode 100644 index bc1dfaf899..0000000000 --- a/src/node/node_grpc.cc +++ /dev/null @@ -1,180 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include -#include "grpc/grpc.h" - -#include "call.h" -#include "channel.h" -#include "event.h" -#include "server.h" -#include "completion_queue_async_worker.h" -#include "credentials.h" -#include "server_credentials.h" - -using v8::Handle; -using v8::Value; -using v8::Object; -using v8::Uint32; -using v8::String; - -void InitStatusConstants(Handle exports) { - NanScope(); - Handle status = Object::New(); - exports->Set(NanNew("status"), status); - Handle OK(NanNew(GRPC_STATUS_OK)); - status->Set(NanNew("OK"), OK); - Handle CANCELLED(NanNew(GRPC_STATUS_CANCELLED)); - status->Set(NanNew("CANCELLED"), CANCELLED); - Handle UNKNOWN(NanNew(GRPC_STATUS_UNKNOWN)); - status->Set(NanNew("UNKNOWN"), UNKNOWN); - Handle INVALID_ARGUMENT( - NanNew(GRPC_STATUS_INVALID_ARGUMENT)); - status->Set(NanNew("INVALID_ARGUMENT"), INVALID_ARGUMENT); - Handle DEADLINE_EXCEEDED( - NanNew(GRPC_STATUS_DEADLINE_EXCEEDED)); - status->Set(NanNew("DEADLINE_EXCEEDED"), DEADLINE_EXCEEDED); - Handle NOT_FOUND(NanNew(GRPC_STATUS_NOT_FOUND)); - status->Set(NanNew("NOT_FOUND"), NOT_FOUND); - Handle ALREADY_EXISTS( - NanNew(GRPC_STATUS_ALREADY_EXISTS)); - status->Set(NanNew("ALREADY_EXISTS"), ALREADY_EXISTS); - Handle PERMISSION_DENIED( - NanNew(GRPC_STATUS_PERMISSION_DENIED)); - status->Set(NanNew("PERMISSION_DENIED"), PERMISSION_DENIED); - Handle UNAUTHENTICATED( - NanNew(GRPC_STATUS_UNAUTHENTICATED)); - status->Set(NanNew("UNAUTHENTICATED"), UNAUTHENTICATED); - Handle RESOURCE_EXHAUSTED( - NanNew(GRPC_STATUS_RESOURCE_EXHAUSTED)); - status->Set(NanNew("RESOURCE_EXHAUSTED"), RESOURCE_EXHAUSTED); - Handle FAILED_PRECONDITION( - NanNew(GRPC_STATUS_FAILED_PRECONDITION)); - status->Set(NanNew("FAILED_PRECONDITION"), FAILED_PRECONDITION); - Handle ABORTED(NanNew(GRPC_STATUS_ABORTED)); - status->Set(NanNew("ABORTED"), ABORTED); - Handle OUT_OF_RANGE( - NanNew(GRPC_STATUS_OUT_OF_RANGE)); - status->Set(NanNew("OUT_OF_RANGE"), OUT_OF_RANGE); - Handle UNIMPLEMENTED( - NanNew(GRPC_STATUS_UNIMPLEMENTED)); - status->Set(NanNew("UNIMPLEMENTED"), UNIMPLEMENTED); - Handle INTERNAL(NanNew(GRPC_STATUS_INTERNAL)); - status->Set(NanNew("INTERNAL"), INTERNAL); - Handle UNAVAILABLE(NanNew(GRPC_STATUS_UNAVAILABLE)); - status->Set(NanNew("UNAVAILABLE"), UNAVAILABLE); - Handle DATA_LOSS(NanNew(GRPC_STATUS_DATA_LOSS)); - status->Set(NanNew("DATA_LOSS"), DATA_LOSS); -} - -void InitCallErrorConstants(Handle exports) { - NanScope(); - Handle call_error = Object::New(); - exports->Set(NanNew("callError"), call_error); - Handle OK(NanNew(GRPC_CALL_OK)); - call_error->Set(NanNew("OK"), OK); - Handle ERROR(NanNew(GRPC_CALL_ERROR)); - call_error->Set(NanNew("ERROR"), ERROR); - Handle NOT_ON_SERVER( - NanNew(GRPC_CALL_ERROR_NOT_ON_SERVER)); - call_error->Set(NanNew("NOT_ON_SERVER"), NOT_ON_SERVER); - Handle NOT_ON_CLIENT( - NanNew(GRPC_CALL_ERROR_NOT_ON_CLIENT)); - call_error->Set(NanNew("NOT_ON_CLIENT"), NOT_ON_CLIENT); - Handle ALREADY_INVOKED( - NanNew(GRPC_CALL_ERROR_ALREADY_INVOKED)); - call_error->Set(NanNew("ALREADY_INVOKED"), ALREADY_INVOKED); - Handle NOT_INVOKED( - NanNew(GRPC_CALL_ERROR_NOT_INVOKED)); - call_error->Set(NanNew("NOT_INVOKED"), NOT_INVOKED); - Handle ALREADY_FINISHED( - NanNew(GRPC_CALL_ERROR_ALREADY_FINISHED)); - call_error->Set(NanNew("ALREADY_FINISHED"), ALREADY_FINISHED); - Handle TOO_MANY_OPERATIONS( - NanNew(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS)); - call_error->Set(NanNew("TOO_MANY_OPERATIONS"), TOO_MANY_OPERATIONS); - Handle INVALID_FLAGS( - NanNew(GRPC_CALL_ERROR_INVALID_FLAGS)); - call_error->Set(NanNew("INVALID_FLAGS"), INVALID_FLAGS); -} - -void InitOpErrorConstants(Handle exports) { - NanScope(); - Handle op_error = Object::New(); - exports->Set(NanNew("opError"), op_error); - Handle OK(NanNew(GRPC_OP_OK)); - op_error->Set(NanNew("OK"), OK); - Handle ERROR(NanNew(GRPC_OP_ERROR)); - op_error->Set(NanNew("ERROR"), ERROR); -} - -void InitCompletionTypeConstants(Handle exports) { - NanScope(); - Handle completion_type = Object::New(); - exports->Set(NanNew("completionType"), completion_type); - Handle QUEUE_SHUTDOWN(NanNew(GRPC_QUEUE_SHUTDOWN)); - completion_type->Set(NanNew("QUEUE_SHUTDOWN"), QUEUE_SHUTDOWN); - Handle READ(NanNew(GRPC_READ)); - completion_type->Set(NanNew("READ"), READ); - Handle WRITE_ACCEPTED(NanNew(GRPC_WRITE_ACCEPTED)); - completion_type->Set(NanNew("WRITE_ACCEPTED"), WRITE_ACCEPTED); - Handle FINISH_ACCEPTED(NanNew(GRPC_FINISH_ACCEPTED)); - completion_type->Set(NanNew("FINISH_ACCEPTED"), FINISH_ACCEPTED); - Handle CLIENT_METADATA_READ( - NanNew(GRPC_CLIENT_METADATA_READ)); - completion_type->Set(NanNew("CLIENT_METADATA_READ"), CLIENT_METADATA_READ); - Handle FINISHED(NanNew(GRPC_FINISHED)); - completion_type->Set(NanNew("FINISHED"), FINISHED); - Handle SERVER_RPC_NEW(NanNew(GRPC_SERVER_RPC_NEW)); - completion_type->Set(NanNew("SERVER_RPC_NEW"), SERVER_RPC_NEW); -} - -void init(Handle exports) { - NanScope(); - grpc_init(); - InitStatusConstants(exports); - InitCallErrorConstants(exports); - InitOpErrorConstants(exports); - InitCompletionTypeConstants(exports); - - grpc::node::Call::Init(exports); - grpc::node::Channel::Init(exports); - grpc::node::Server::Init(exports); - grpc::node::CompletionQueueAsyncWorker::Init(exports); - grpc::node::Credentials::Init(exports); - grpc::node::ServerCredentials::Init(exports); -} - -NODE_MODULE(grpc, init) diff --git a/src/node/server.cc b/src/node/server.cc deleted file mode 100644 index b102775d33..0000000000 --- a/src/node/server.cc +++ /dev/null @@ -1,236 +0,0 @@ -/* - * - * Copyright 2014, 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 "server.h" - -#include -#include - -#include - -#include -#include "grpc/grpc.h" -#include "grpc/grpc_security.h" -#include "call.h" -#include "completion_queue_async_worker.h" -#include "tag.h" -#include "server_credentials.h" - -namespace grpc { -namespace node { - -using v8::Arguments; -using v8::Array; -using v8::Boolean; -using v8::Exception; -using v8::Function; -using v8::FunctionTemplate; -using v8::Handle; -using v8::HandleScope; -using v8::Local; -using v8::Number; -using v8::Object; -using v8::Persistent; -using v8::String; -using v8::Value; - -Persistent Server::constructor; -Persistent Server::fun_tpl; - -Server::Server(grpc_server *server) : wrapped_server(server) {} - -Server::~Server() { grpc_server_destroy(wrapped_server); } - -void Server::Init(Handle exports) { - NanScope(); - Local tpl = FunctionTemplate::New(New); - tpl->SetClassName(String::NewSymbol("Server")); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - NanSetPrototypeTemplate(tpl, "requestCall", - FunctionTemplate::New(RequestCall)->GetFunction()); - - NanSetPrototypeTemplate(tpl, "addHttp2Port", - FunctionTemplate::New(AddHttp2Port)->GetFunction()); - - NanSetPrototypeTemplate( - tpl, "addSecureHttp2Port", - FunctionTemplate::New(AddSecureHttp2Port)->GetFunction()); - - NanSetPrototypeTemplate(tpl, "start", - FunctionTemplate::New(Start)->GetFunction()); - - NanSetPrototypeTemplate(tpl, "shutdown", - FunctionTemplate::New(Shutdown)->GetFunction()); - - NanAssignPersistent(fun_tpl, tpl); - NanAssignPersistent(constructor, tpl->GetFunction()); - exports->Set(String::NewSymbol("Server"), constructor); -} - -bool Server::HasInstance(Handle val) { - return NanHasInstance(fun_tpl, val); -} - -NAN_METHOD(Server::New) { - NanScope(); - - /* If this is not a constructor call, make a constructor call and return - the result */ - if (!args.IsConstructCall()) { - const int argc = 1; - Local argv[argc] = {args[0]}; - NanReturnValue(constructor->NewInstance(argc, argv)); - } - grpc_server *wrapped_server; - grpc_completion_queue *queue = CompletionQueueAsyncWorker::GetQueue(); - if (args[0]->IsUndefined()) { - wrapped_server = grpc_server_create(queue, NULL); - } else if (args[0]->IsObject()) { - grpc_server_credentials *creds = NULL; - Handle args_hash(args[0]->ToObject()->Clone()); - if (args_hash->HasOwnProperty(NanNew("credentials"))) { - Handle creds_value = args_hash->Get(NanNew("credentials")); - if (!ServerCredentials::HasInstance(creds_value)) { - return NanThrowTypeError( - "credentials arg must be a ServerCredentials object"); - } - ServerCredentials *creds_object = - ObjectWrap::Unwrap(creds_value->ToObject()); - creds = creds_object->GetWrappedServerCredentials(); - args_hash->Delete(NanNew("credentials")); - } - Handle keys(args_hash->GetOwnPropertyNames()); - grpc_channel_args channel_args; - channel_args.num_args = keys->Length(); - channel_args.args = reinterpret_cast( - calloc(channel_args.num_args, sizeof(grpc_arg))); - /* These are used to keep all strings until then end of the block, then - destroy them */ - std::vector key_strings(keys->Length()); - std::vector value_strings(keys->Length()); - for (unsigned int i = 0; i < channel_args.num_args; i++) { - Handle current_key(keys->Get(i)->ToString()); - Handle current_value(args_hash->Get(current_key)); - key_strings[i] = new NanUtf8String(current_key); - channel_args.args[i].key = **key_strings[i]; - if (current_value->IsInt32()) { - channel_args.args[i].type = GRPC_ARG_INTEGER; - channel_args.args[i].value.integer = current_value->Int32Value(); - } else if (current_value->IsString()) { - channel_args.args[i].type = GRPC_ARG_STRING; - value_strings[i] = new NanUtf8String(current_value); - channel_args.args[i].value.string = **value_strings[i]; - } else { - free(channel_args.args); - return NanThrowTypeError("Arg values must be strings"); - } - } - if (creds == NULL) { - wrapped_server = grpc_server_create(queue, &channel_args); - } else { - wrapped_server = grpc_secure_server_create(creds, queue, &channel_args); - } - free(channel_args.args); - } else { - return NanThrowTypeError("Server expects an object"); - } - Server *server = new Server(wrapped_server); - server->Wrap(args.This()); - NanReturnValue(args.This()); -} - -NAN_METHOD(Server::RequestCall) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError("requestCall can only be called on a Server"); - } - Server *server = ObjectWrap::Unwrap(args.This()); - grpc_call_error error = grpc_server_request_call( - server->wrapped_server, CreateTag(args[0], NanNull())); - if (error == GRPC_CALL_OK) { - CompletionQueueAsyncWorker::Next(); - } else { - return NanThrowError("requestCall failed", error); - } - NanReturnUndefined(); -} - -NAN_METHOD(Server::AddHttp2Port) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError("addHttp2Port can only be called on a Server"); - } - if (!args[0]->IsString()) { - return NanThrowTypeError("addHttp2Port's argument must be a String"); - } - Server *server = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(grpc_server_add_http2_port( - server->wrapped_server, *NanUtf8String(args[0])))); -} - -NAN_METHOD(Server::AddSecureHttp2Port) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError( - "addSecureHttp2Port can only be called on a Server"); - } - if (!args[0]->IsString()) { - return NanThrowTypeError("addSecureHttp2Port's argument must be a String"); - } - Server *server = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(grpc_server_add_secure_http2_port( - server->wrapped_server, *NanUtf8String(args[0])))); -} - -NAN_METHOD(Server::Start) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError("start can only be called on a Server"); - } - Server *server = ObjectWrap::Unwrap(args.This()); - grpc_server_start(server->wrapped_server); - NanReturnUndefined(); -} - -NAN_METHOD(Server::Shutdown) { - NanScope(); - if (!HasInstance(args.This())) { - return NanThrowTypeError("shutdown can only be called on a Server"); - } - Server *server = ObjectWrap::Unwrap(args.This()); - grpc_server_shutdown(server->wrapped_server); - NanReturnUndefined(); -} - -} // namespace node -} // namespace grpc diff --git a/src/node/server.h b/src/node/server.h deleted file mode 100644 index d50f1fb6c5..0000000000 --- a/src/node/server.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef NET_GRPC_NODE_SERVER_H_ -#define NET_GRPC_NODE_SERVER_H_ - -#include -#include -#include "grpc/grpc.h" - -namespace grpc { -namespace node { - -/* Wraps grpc_server as a JavaScript object. Provides a constructor - and wrapper methods for grpc_server_create, grpc_server_request_call, - grpc_server_add_http2_port, and grpc_server_start. */ -class Server : public ::node::ObjectWrap { - public: - /* Initializes the Server class and exposes the constructor and - wrapper methods to JavaScript */ - static void Init(v8::Handle exports); - /* Tests whether the given value was constructed by this class's - JavaScript constructor */ - static bool HasInstance(v8::Handle val); - - private: - explicit Server(grpc_server *server); - ~Server(); - - // Prevent copying - Server(const Server &); - Server &operator=(const Server &); - - static NAN_METHOD(New); - static NAN_METHOD(RequestCall); - static NAN_METHOD(AddHttp2Port); - static NAN_METHOD(AddSecureHttp2Port); - static NAN_METHOD(Start); - static NAN_METHOD(Shutdown); - static v8::Persistent constructor; - static v8::Persistent fun_tpl; - - grpc_server *wrapped_server; -}; - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_SERVER_H_ diff --git a/src/node/server.js b/src/node/server.js deleted file mode 100644 index 03cdbe6f98..0000000000 --- a/src/node/server.js +++ /dev/null @@ -1,314 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -var _ = require('underscore'); - -var grpc = require('bindings')('grpc.node'); - -var common = require('./common'); - -var Duplex = require('stream').Duplex; -var util = require('util'); - -util.inherits(GrpcServerStream, Duplex); - -/** - * Class for representing a gRPC server side stream as a Node stream. Extends - * from stream.Duplex. - * @constructor - * @param {grpc.Call} call Call object to proxy - * @param {function(*):Buffer=} serialize Serialization function for responses - * @param {function(Buffer):*=} deserialize Deserialization function for - * requests - */ -function GrpcServerStream(call, serialize, deserialize) { - Duplex.call(this, {objectMode: true}); - if (!serialize) { - serialize = function(value) { - return value; - }; - } - if (!deserialize) { - deserialize = function(value) { - return value; - }; - } - this._call = call; - // Indicate that a status has been sent - var finished = false; - var self = this; - var status = { - 'code' : grpc.status.OK, - 'details' : 'OK' - }; - - /** - * Serialize a response value to a buffer. Always maps null to null. Otherwise - * uses the provided serialize function - * @param {*} value The value to serialize - * @return {Buffer} The serialized value - */ - this.serialize = function(value) { - if (value === null || value === undefined) { - return null; - } - return serialize(value); - }; - - /** - * Deserialize a request buffer to a value. Always maps null to null. - * Otherwise uses the provided deserialize function. - * @param {Buffer} buffer The buffer to deserialize - * @return {*} The deserialized value - */ - this.deserialize = function(buffer) { - if (buffer === null) { - return null; - } - return deserialize(buffer); - }; - - /** - * Send the pending status - */ - function sendStatus() { - call.startWriteStatus(status.code, status.details, function() { - }); - finished = true; - } - this.on('finish', sendStatus); - /** - * Set the pending status to a given error status. If the error does not have - * code or details properties, the code will be set to grpc.status.INTERNAL - * and the details will be set to 'Unknown Error'. - * @param {Error} err The error object - */ - function setStatus(err) { - var code = grpc.status.INTERNAL; - var details = 'Unknown Error'; - - if (err.hasOwnProperty('code')) { - code = err.code; - if (err.hasOwnProperty('details')) { - details = err.details; - } - } - status = {'code': code, 'details': details}; - } - /** - * Terminate the call. This includes indicating that reads are done, draining - * all pending writes, and sending the given error as a status - * @param {Error} err The error object - * @this GrpcServerStream - */ - function terminateCall(err) { - // Drain readable data - this.on('data', function() {}); - setStatus(err); - this.end(); - } - this.on('error', terminateCall); - // Indicates that a read is pending - var reading = false; - /** - * Callback to be called when a READ event is received. Pushes the data onto - * the read queue and starts reading again if applicable - * @param {grpc.Event} event READ event object - */ - function readCallback(event) { - if (finished) { - self.push(null); - return; - } - var data = event.data; - if (self.push(self.deserialize(data)) && data != null) { - self._call.startRead(readCallback); - } else { - reading = false; - } - } - /** - * Start reading if there is not already a pending read. Reading will - * continue until self.push returns false (indicating reads should slow - * down) or the read data is null (indicating that there is no more data). - */ - this.startReading = function() { - if (finished) { - self.push(null); - } else { - if (!reading) { - reading = true; - self._call.startRead(readCallback); - } - } - }; -} - -/** - * Start reading from the gRPC data source. This is an implementation of a - * method required for implementing stream.Readable - * @param {number} size Ignored - */ -GrpcServerStream.prototype._read = function(size) { - this.startReading(); -}; - -/** - * Start writing a chunk of data. This is an implementation of a method required - * for implementing stream.Writable. - * @param {Buffer} chunk The chunk of data to write - * @param {string} encoding Ignored - * @param {function(Error=)} callback Callback to indicate that the write is - * complete - */ -GrpcServerStream.prototype._write = function(chunk, encoding, callback) { - var self = this; - self._call.startWrite(self.serialize(chunk), function(event) { - callback(); - }, 0); -}; - -/** - * Constructs a server object that stores request handlers and delegates - * incoming requests to those handlers - * @constructor - * @param {Array} options Options that should be passed to the internal server - * implementation - */ -function Server(options) { - this.handlers = {}; - var handlers = this.handlers; - var server = new grpc.Server(options); - this._server = server; - var started = false; - /** - * Start the server and begin handling requests - * @this Server - */ - this.start = function() { - console.log('Server starting'); - _.each(handlers, function(handler, handler_name) { - console.log('Serving', handler_name); - }); - if (this.started) { - throw 'Server is already running'; - } - server.start(); - /** - * Handles the SERVER_RPC_NEW event. If there is a handler associated with - * the requested method, use that handler to respond to the request. Then - * wait for the next request - * @param {grpc.Event} event The event to handle with tag SERVER_RPC_NEW - */ - function handleNewCall(event) { - var call = event.call; - var data = event.data; - if (data === null) { - return; - } - server.requestCall(handleNewCall); - var handler = undefined; - var deadline = data.absolute_deadline; - var cancelled = false; - if (handlers.hasOwnProperty(data.method)) { - handler = handlers[data.method]; - } - call.serverAccept(function(event) { - if (event.data.code === grpc.status.CANCELLED) { - cancelled = true; - stream.emit('cancelled'); - } - }, 0); - call.serverEndInitialMetadata(0); - var stream = new GrpcServerStream(call, handler.serialize, - handler.deserialize); - Object.defineProperty(stream, 'cancelled', { - get: function() { return cancelled;} - }); - try { - handler.func(stream, data.metadata); - } catch (e) { - stream.emit('error', e); - } - } - server.requestCall(handleNewCall); - }; - /** Shuts down the server. - */ - this.shutdown = function() { - server.shutdown(); - }; -} - -/** - * Registers a handler to handle the named method. Fails if there already is - * a handler for the given method. Returns true on success - * @param {string} name The name of the method that the provided function should - * handle/respond to. - * @param {function} handler Function that takes a stream of request values and - * returns a stream of response values - * @param {function(*):Buffer} serialize Serialization function for responses - * @param {function(Buffer):*} deserialize Deserialization function for requests - * @return {boolean} True if the handler was set. False if a handler was already - * set for that name. - */ -Server.prototype.register = function(name, handler, serialize, deserialize) { - if (this.handlers.hasOwnProperty(name)) { - return false; - } - this.handlers[name] = { - func: handler, - serialize: serialize, - deserialize: deserialize - }; - return true; -}; - -/** - * Binds the server to the given port, with SSL enabled if secure is specified - * @param {string} port The port that the server should bind on, in the format - * "address:port" - * @param {boolean=} secure Whether the server should open a secure port - */ -Server.prototype.bind = function(port, secure) { - if (secure) { - return this._server.addSecureHttp2Port(port); - } else { - return this._server.addHttp2Port(port); - } -}; - -/** - * See documentation for Server - */ -module.exports = Server; diff --git a/src/node/server_credentials.cc b/src/node/server_credentials.cc deleted file mode 100644 index 393f3a6305..0000000000 --- a/src/node/server_credentials.cc +++ /dev/null @@ -1,155 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#include "grpc/grpc.h" -#include "grpc/grpc_security.h" -#include "grpc/support/log.h" -#include "server_credentials.h" - -namespace grpc { -namespace node { - -using ::node::Buffer; -using v8::Arguments; -using v8::Exception; -using v8::External; -using v8::Function; -using v8::FunctionTemplate; -using v8::Handle; -using v8::HandleScope; -using v8::Integer; -using v8::Local; -using v8::Object; -using v8::ObjectTemplate; -using v8::Persistent; -using v8::Value; - -Persistent ServerCredentials::constructor; -Persistent ServerCredentials::fun_tpl; - -ServerCredentials::ServerCredentials(grpc_server_credentials *credentials) - : wrapped_credentials(credentials) {} - -ServerCredentials::~ServerCredentials() { - gpr_log(GPR_DEBUG, "Destroying server credentials object"); - grpc_server_credentials_release(wrapped_credentials); -} - -void ServerCredentials::Init(Handle exports) { - NanScope(); - Local tpl = FunctionTemplate::New(New); - tpl->SetClassName(NanNew("ServerCredentials")); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - NanAssignPersistent(fun_tpl, tpl); - NanAssignPersistent(constructor, tpl->GetFunction()); - constructor->Set(NanNew("createSsl"), - FunctionTemplate::New(CreateSsl)->GetFunction()); - constructor->Set(NanNew("createFake"), - FunctionTemplate::New(CreateFake)->GetFunction()); - exports->Set(NanNew("ServerCredentials"), constructor); -} - -bool ServerCredentials::HasInstance(Handle val) { - NanScope(); - return NanHasInstance(fun_tpl, val); -} - -Handle ServerCredentials::WrapStruct( - grpc_server_credentials *credentials) { - NanEscapableScope(); - if (credentials == NULL) { - return NanEscapeScope(NanNull()); - } - const int argc = 1; - Handle argv[argc] = { - External::New(reinterpret_cast(credentials))}; - return NanEscapeScope(constructor->NewInstance(argc, argv)); -} - -grpc_server_credentials *ServerCredentials::GetWrappedServerCredentials() { - return wrapped_credentials; -} - -NAN_METHOD(ServerCredentials::New) { - NanScope(); - - if (args.IsConstructCall()) { - if (!args[0]->IsExternal()) { - return NanThrowTypeError( - "ServerCredentials can only be created with the provide functions"); - } - grpc_server_credentials *creds_value = - reinterpret_cast(External::Unwrap(args[0])); - ServerCredentials *credentials = new ServerCredentials(creds_value); - credentials->Wrap(args.This()); - NanReturnValue(args.This()); - } else { - const int argc = 1; - Local argv[argc] = {args[0]}; - NanReturnValue(constructor->NewInstance(argc, argv)); - } -} - -NAN_METHOD(ServerCredentials::CreateSsl) { - // TODO: have the node API support multiple key/cert pairs. - NanScope(); - char *root_certs = NULL; - grpc_ssl_pem_key_cert_pair key_cert_pair; - if (Buffer::HasInstance(args[0])) { - root_certs = Buffer::Data(args[0]); - } else if (!(args[0]->IsNull() || args[0]->IsUndefined())) { - return NanThrowTypeError( - "createSSl's first argument must be a Buffer if provided"); - } - if (!Buffer::HasInstance(args[1])) { - return NanThrowTypeError("createSsl's second argument must be a Buffer"); - } - key_cert_pair.private_key = Buffer::Data(args[1]); - if (!Buffer::HasInstance(args[2])) { - return NanThrowTypeError("createSsl's third argument must be a Buffer"); - } - key_cert_pair.cert_chain = Buffer::Data(args[2]); - 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())); -} - -} // namespace node -} // namespace grpc diff --git a/src/node/server_credentials.h b/src/node/server_credentials.h deleted file mode 100644 index 8baae3f185..0000000000 --- a/src/node/server_credentials.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef NET_GRPC_NODE_SERVER_CREDENTIALS_H_ -#define NET_GRPC_NODE_SERVER_CREDENTIALS_H_ - -#include -#include -#include "grpc/grpc.h" -#include "grpc/grpc_security.h" - -namespace grpc { -namespace node { - -/* Wrapper class for grpc_server_credentials structs */ -class ServerCredentials : public ::node::ObjectWrap { - public: - static void Init(v8::Handle exports); - static bool HasInstance(v8::Handle val); - /* Wrap a grpc_server_credentials struct in a javascript object */ - static v8::Handle WrapStruct(grpc_server_credentials *credentials); - - /* Returns the grpc_server_credentials struct that this object wraps */ - grpc_server_credentials *GetWrappedServerCredentials(); - - private: - explicit ServerCredentials(grpc_server_credentials *credentials); - ~ServerCredentials(); - - // Prevent copying - ServerCredentials(const ServerCredentials &); - ServerCredentials &operator=(const ServerCredentials &); - - static NAN_METHOD(New); - static NAN_METHOD(CreateSsl); - static NAN_METHOD(CreateFake); - static v8::Persistent constructor; - // Used for typechecking instances of this javascript class - static v8::Persistent fun_tpl; - - grpc_server_credentials *wrapped_credentials; -}; - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_SERVER_CREDENTIALS_H_ diff --git a/src/node/src/client.js b/src/node/src/client.js new file mode 100644 index 0000000000..3a1c9eef84 --- /dev/null +++ b/src/node/src/client.js @@ -0,0 +1,215 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +var grpc = require('bindings')('grpc.node'); + +var common = require('./common'); + +var Duplex = require('stream').Duplex; +var util = require('util'); + +util.inherits(GrpcClientStream, Duplex); + +/** + * Class for representing a gRPC client side stream as a Node stream. Extends + * from stream.Duplex. + * @constructor + * @param {grpc.Call} call Call object to proxy + * @param {function(*):Buffer=} serialize Serialization function for requests + * @param {function(Buffer):*=} deserialize Deserialization function for + * responses + */ +function GrpcClientStream(call, serialize, deserialize) { + Duplex.call(this, {objectMode: true}); + if (!serialize) { + serialize = function(value) { + return value; + }; + } + if (!deserialize) { + deserialize = function(value) { + return value; + }; + } + var self = this; + var finished = false; + // Indicates that a read is currently pending + var reading = false; + // Indicates that a write is currently pending + var writing = false; + this._call = call; + + /** + * Serialize a request value to a buffer. Always maps null to null. Otherwise + * uses the provided serialize function + * @param {*} value The value to serialize + * @return {Buffer} The serialized value + */ + this.serialize = function(value) { + if (value === null || value === undefined) { + return null; + } + return serialize(value); + }; + + /** + * Deserialize a response buffer to a value. Always maps null to null. + * Otherwise uses the provided deserialize function. + * @param {Buffer} buffer The buffer to deserialize + * @return {*} The deserialized value + */ + this.deserialize = function(buffer) { + if (buffer === null) { + return null; + } + return deserialize(buffer); + }; + /** + * Callback to be called when a READ event is received. Pushes the data onto + * the read queue and starts reading again if applicable + * @param {grpc.Event} event READ event object + */ + function readCallback(event) { + if (finished) { + self.push(null); + return; + } + var data = event.data; + if (self.push(self.deserialize(data)) && data != null) { + self._call.startRead(readCallback); + } else { + reading = false; + } + } + call.invoke(function(event) { + self.emit('metadata', event.data); + }, function(event) { + finished = true; + self.emit('status', event.data); + }, 0); + this.on('finish', function() { + call.writesDone(function() {}); + }); + /** + * Start reading if there is not already a pending read. Reading will + * continue until self.push returns false (indicating reads should slow + * down) or the read data is null (indicating that there is no more data). + */ + this.startReading = function() { + if (finished) { + self.push(null); + } else { + if (!reading) { + reading = true; + self._call.startRead(readCallback); + } + } + }; +} + +/** + * Start reading. This is an implementation of a method needed for implementing + * stream.Readable. + * @param {number} size Ignored + */ +GrpcClientStream.prototype._read = function(size) { + this.startReading(); +}; + +/** + * Attempt to write the given chunk. Calls the callback when done. This is an + * implementation of a method needed for implementing stream.Writable. + * @param {Buffer} chunk The chunk to write + * @param {string} encoding Ignored + * @param {function(Error=)} callback Ignored + */ +GrpcClientStream.prototype._write = function(chunk, encoding, callback) { + var self = this; + self._call.startWrite(self.serialize(chunk), function(event) { + callback(); + }, 0); +}; + +/** + * Cancel the ongoing call. If the call has not already finished, it will finish + * with status CANCELLED. + */ +GrpcClientStream.prototype.cancel = function() { + this._call.cancel(); +}; + +/** + * Make a request on the channel to the given method with the given arguments + * @param {grpc.Channel} channel The channel on which to make the request + * @param {string} method The method to request + * @param {function(*):Buffer} serialize Serialization function for requests + * @param {function(Buffer):*} deserialize Deserialization function for + * responses + * @param {array=} metadata Array of metadata key/value pairs to add to the call + * @param {(number|Date)=} deadline The deadline for processing this request. + * Defaults to infinite future. + * @return {stream=} The stream of responses + */ +function makeRequest(channel, + method, + serialize, + deserialize, + metadata, + deadline) { + if (deadline === undefined) { + deadline = Infinity; + } + var call = new grpc.Call(channel, method, deadline); + if (metadata) { + call.addMetadata(metadata); + } + return new GrpcClientStream(call, serialize, deserialize); +} + +/** + * See documentation for makeRequest above + */ +exports.makeRequest = makeRequest; + +/** + * Represents a client side gRPC channel associated with a single host. + */ +exports.Channel = grpc.Channel; +/** + * Status name to code number mapping + */ +exports.status = grpc.status; +/** + * Call error name to code number mapping + */ +exports.callError = grpc.callError; diff --git a/src/node/src/common.js b/src/node/src/common.js new file mode 100644 index 0000000000..54247e3fa1 --- /dev/null +++ b/src/node/src/common.js @@ -0,0 +1,103 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +var capitalize = require('underscore.string/capitalize'); + +/** + * Get a function that deserializes a specific type of protobuf. + * @param {function()} cls The constructor of the message type to deserialize + * @return {function(Buffer):cls} The deserialization function + */ +function deserializeCls(cls) { + /** + * Deserialize a buffer to a message object + * @param {Buffer} arg_buf The buffer to deserialize + * @return {cls} The resulting object + */ + return function deserialize(arg_buf) { + return cls.decode(arg_buf); + }; +} + +/** + * 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) { + /** + * Serialize an object to a Buffer + * @param {Object} arg The object to serialize + * @return {Buffer} The serialized object + */ + return function serialize(arg) { + return new Buffer(new Cls(arg).encode().toBuffer()); + }; +} + +/** + * 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) { + if (value === null || value === undefined) { + return ''; + } + var name = value.name; + if (value.className === 'Service.RPCMethod') { + name = capitalize(name); + } + if (value.hasOwnProperty('parent')) { + var parent_name = fullyQualifiedName(value.parent); + if (parent_name !== '') { + name = parent_name + '.' + name; + } + } + return name; +} + +/** + * See docs for deserializeCls + */ +exports.deserializeCls = deserializeCls; + +/** + * See docs for serializeCls + */ +exports.serializeCls = serializeCls; + +/** + * See docs for fullyQualifiedName + */ +exports.fullyQualifiedName = fullyQualifiedName; diff --git a/src/node/src/server.js b/src/node/src/server.js new file mode 100644 index 0000000000..03cdbe6f98 --- /dev/null +++ b/src/node/src/server.js @@ -0,0 +1,314 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +var _ = require('underscore'); + +var grpc = require('bindings')('grpc.node'); + +var common = require('./common'); + +var Duplex = require('stream').Duplex; +var util = require('util'); + +util.inherits(GrpcServerStream, Duplex); + +/** + * Class for representing a gRPC server side stream as a Node stream. Extends + * from stream.Duplex. + * @constructor + * @param {grpc.Call} call Call object to proxy + * @param {function(*):Buffer=} serialize Serialization function for responses + * @param {function(Buffer):*=} deserialize Deserialization function for + * requests + */ +function GrpcServerStream(call, serialize, deserialize) { + Duplex.call(this, {objectMode: true}); + if (!serialize) { + serialize = function(value) { + return value; + }; + } + if (!deserialize) { + deserialize = function(value) { + return value; + }; + } + this._call = call; + // Indicate that a status has been sent + var finished = false; + var self = this; + var status = { + 'code' : grpc.status.OK, + 'details' : 'OK' + }; + + /** + * Serialize a response value to a buffer. Always maps null to null. Otherwise + * uses the provided serialize function + * @param {*} value The value to serialize + * @return {Buffer} The serialized value + */ + this.serialize = function(value) { + if (value === null || value === undefined) { + return null; + } + return serialize(value); + }; + + /** + * Deserialize a request buffer to a value. Always maps null to null. + * Otherwise uses the provided deserialize function. + * @param {Buffer} buffer The buffer to deserialize + * @return {*} The deserialized value + */ + this.deserialize = function(buffer) { + if (buffer === null) { + return null; + } + return deserialize(buffer); + }; + + /** + * Send the pending status + */ + function sendStatus() { + call.startWriteStatus(status.code, status.details, function() { + }); + finished = true; + } + this.on('finish', sendStatus); + /** + * Set the pending status to a given error status. If the error does not have + * code or details properties, the code will be set to grpc.status.INTERNAL + * and the details will be set to 'Unknown Error'. + * @param {Error} err The error object + */ + function setStatus(err) { + var code = grpc.status.INTERNAL; + var details = 'Unknown Error'; + + if (err.hasOwnProperty('code')) { + code = err.code; + if (err.hasOwnProperty('details')) { + details = err.details; + } + } + status = {'code': code, 'details': details}; + } + /** + * Terminate the call. This includes indicating that reads are done, draining + * all pending writes, and sending the given error as a status + * @param {Error} err The error object + * @this GrpcServerStream + */ + function terminateCall(err) { + // Drain readable data + this.on('data', function() {}); + setStatus(err); + this.end(); + } + this.on('error', terminateCall); + // Indicates that a read is pending + var reading = false; + /** + * Callback to be called when a READ event is received. Pushes the data onto + * the read queue and starts reading again if applicable + * @param {grpc.Event} event READ event object + */ + function readCallback(event) { + if (finished) { + self.push(null); + return; + } + var data = event.data; + if (self.push(self.deserialize(data)) && data != null) { + self._call.startRead(readCallback); + } else { + reading = false; + } + } + /** + * Start reading if there is not already a pending read. Reading will + * continue until self.push returns false (indicating reads should slow + * down) or the read data is null (indicating that there is no more data). + */ + this.startReading = function() { + if (finished) { + self.push(null); + } else { + if (!reading) { + reading = true; + self._call.startRead(readCallback); + } + } + }; +} + +/** + * Start reading from the gRPC data source. This is an implementation of a + * method required for implementing stream.Readable + * @param {number} size Ignored + */ +GrpcServerStream.prototype._read = function(size) { + this.startReading(); +}; + +/** + * Start writing a chunk of data. This is an implementation of a method required + * for implementing stream.Writable. + * @param {Buffer} chunk The chunk of data to write + * @param {string} encoding Ignored + * @param {function(Error=)} callback Callback to indicate that the write is + * complete + */ +GrpcServerStream.prototype._write = function(chunk, encoding, callback) { + var self = this; + self._call.startWrite(self.serialize(chunk), function(event) { + callback(); + }, 0); +}; + +/** + * Constructs a server object that stores request handlers and delegates + * incoming requests to those handlers + * @constructor + * @param {Array} options Options that should be passed to the internal server + * implementation + */ +function Server(options) { + this.handlers = {}; + var handlers = this.handlers; + var server = new grpc.Server(options); + this._server = server; + var started = false; + /** + * Start the server and begin handling requests + * @this Server + */ + this.start = function() { + console.log('Server starting'); + _.each(handlers, function(handler, handler_name) { + console.log('Serving', handler_name); + }); + if (this.started) { + throw 'Server is already running'; + } + server.start(); + /** + * Handles the SERVER_RPC_NEW event. If there is a handler associated with + * the requested method, use that handler to respond to the request. Then + * wait for the next request + * @param {grpc.Event} event The event to handle with tag SERVER_RPC_NEW + */ + function handleNewCall(event) { + var call = event.call; + var data = event.data; + if (data === null) { + return; + } + server.requestCall(handleNewCall); + var handler = undefined; + var deadline = data.absolute_deadline; + var cancelled = false; + if (handlers.hasOwnProperty(data.method)) { + handler = handlers[data.method]; + } + call.serverAccept(function(event) { + if (event.data.code === grpc.status.CANCELLED) { + cancelled = true; + stream.emit('cancelled'); + } + }, 0); + call.serverEndInitialMetadata(0); + var stream = new GrpcServerStream(call, handler.serialize, + handler.deserialize); + Object.defineProperty(stream, 'cancelled', { + get: function() { return cancelled;} + }); + try { + handler.func(stream, data.metadata); + } catch (e) { + stream.emit('error', e); + } + } + server.requestCall(handleNewCall); + }; + /** Shuts down the server. + */ + this.shutdown = function() { + server.shutdown(); + }; +} + +/** + * Registers a handler to handle the named method. Fails if there already is + * a handler for the given method. Returns true on success + * @param {string} name The name of the method that the provided function should + * handle/respond to. + * @param {function} handler Function that takes a stream of request values and + * returns a stream of response values + * @param {function(*):Buffer} serialize Serialization function for responses + * @param {function(Buffer):*} deserialize Deserialization function for requests + * @return {boolean} True if the handler was set. False if a handler was already + * set for that name. + */ +Server.prototype.register = function(name, handler, serialize, deserialize) { + if (this.handlers.hasOwnProperty(name)) { + return false; + } + this.handlers[name] = { + func: handler, + serialize: serialize, + deserialize: deserialize + }; + return true; +}; + +/** + * Binds the server to the given port, with SSL enabled if secure is specified + * @param {string} port The port that the server should bind on, in the format + * "address:port" + * @param {boolean=} secure Whether the server should open a secure port + */ +Server.prototype.bind = function(port, secure) { + if (secure) { + return this._server.addSecureHttp2Port(port); + } else { + return this._server.addHttp2Port(port); + } +}; + +/** + * See documentation for Server + */ +module.exports = Server; diff --git a/src/node/src/surface_client.js b/src/node/src/surface_client.js new file mode 100644 index 0000000000..16c31809f4 --- /dev/null +++ b/src/node/src/surface_client.js @@ -0,0 +1,357 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +var _ = require('underscore'); + +var capitalize = require('underscore.string/capitalize'); +var decapitalize = require('underscore.string/decapitalize'); + +var client = require('./client.js'); + +var common = require('./common.js'); + +var EventEmitter = require('events').EventEmitter; + +var stream = require('stream'); + +var Readable = stream.Readable; +var Writable = stream.Writable; +var Duplex = stream.Duplex; +var util = require('util'); + + +function forwardEvent(fromEmitter, toEmitter, event) { + fromEmitter.on(event, function forward() { + _.partial(toEmitter.emit, event).apply(toEmitter, arguments); + }); +} + +util.inherits(ClientReadableObjectStream, Readable); + +/** + * Class for representing a gRPC server streaming call as a Node stream on the + * client side. Extends from stream.Readable. + * @constructor + * @param {stream} stream Underlying binary Duplex stream for the call + */ +function ClientReadableObjectStream(stream) { + var options = {objectMode: true}; + Readable.call(this, options); + this._stream = stream; + var self = this; + forwardEvent(stream, this, 'status'); + forwardEvent(stream, this, 'metadata'); + this._stream.on('data', function forwardData(chunk) { + if (!self.push(chunk)) { + self._stream.pause(); + } + }); + this._stream.pause(); +} + +/** + * _read implementation for both types of streams that allow reading. + * @this {ClientReadableObjectStream} + * @param {number} size Ignored + */ +function _read(size) { + this._stream.resume(); +} + +/** + * See docs for _read + */ +ClientReadableObjectStream.prototype._read = _read; + +util.inherits(ClientWritableObjectStream, Writable); + +/** + * Class for representing a gRPC client streaming call as a Node stream on the + * client side. Extends from stream.Writable. + * @constructor + * @param {stream} stream Underlying binary Duplex stream for the call + */ +function ClientWritableObjectStream(stream) { + var options = {objectMode: true}; + Writable.call(this, options); + this._stream = stream; + forwardEvent(stream, this, 'status'); + forwardEvent(stream, this, 'metadata'); + this.on('finish', function() { + this._stream.end(); + }); +} + +/** + * _write implementation for both types of streams that allow writing + * @this {ClientWritableObjectStream} + * @param {*} chunk The value to write to the stream + * @param {string} encoding Ignored + * @param {function(Error)} callback Callback to call when finished writing + */ +function _write(chunk, encoding, callback) { + this._stream.write(chunk, encoding, callback); +} + +/** + * See docs for _write + */ +ClientWritableObjectStream.prototype._write = _write; + +/** + * Cancel the underlying call + */ +function cancel() { + this._stream.cancel(); +} + +ClientReadableObjectStream.prototype.cancel = cancel; +ClientWritableObjectStream.prototype.cancel = cancel; + +/** + * 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 + * @param {function(Buffer)} deserialize The deserialization function for + * outputs + * @return {Function} makeUnaryRequest + */ +function makeUnaryRequestFunction(method, serialize, deserialize) { + /** + * Make a unary request with this method on the given channel with the given + * argument, callback, etc. + * @this {SurfaceClient} Client object. Must have a channel member. + * @param {*} argument The argument to the call. Should be serializable with + * serialize + * @param {function(?Error, value=)} callback The callback to for when the + * response is received + * @param {array=} metadata Array of metadata key/value pairs to add to the + * call + * @param {(number|Date)=} deadline The deadline for processing this request. + * Defaults to infinite future + * @return {EventEmitter} An event emitter for stream related events + */ + function makeUnaryRequest(argument, callback, metadata, deadline) { + var stream = client.makeRequest(this.channel, method, serialize, + deserialize, metadata, deadline); + var emitter = new EventEmitter(); + emitter.cancel = function cancel() { + stream.cancel(); + }; + forwardEvent(stream, emitter, 'status'); + forwardEvent(stream, emitter, 'metadata'); + stream.write(argument); + stream.end(); + stream.on('data', function forwardData(chunk) { + try { + callback(null, chunk); + } catch (e) { + callback(e); + } + }); + stream.on('status', function forwardStatus(status) { + if (status.code !== client.status.OK) { + callback(status); + } + }); + return emitter; + } + return makeUnaryRequest; +} + +/** + * Get a function that can make client stream requests to the specified method. + * @param {string} method The name of the method to request + * @param {function(*):Buffer} serialize The serialization function for inputs + * @param {function(Buffer)} deserialize The deserialization function for + * outputs + * @return {Function} makeClientStreamRequest + */ +function makeClientStreamRequestFunction(method, serialize, deserialize) { + /** + * Make a client stream request with this method on the given channel with the + * given callback, etc. + * @this {SurfaceClient} Client object. Must have a channel member. + * @param {function(?Error, value=)} callback The callback to for when the + * response is received + * @param {array=} metadata Array of metadata key/value pairs to add to the + * call + * @param {(number|Date)=} deadline The deadline for processing this request. + * Defaults to infinite future + * @return {EventEmitter} An event emitter for stream related events + */ + function makeClientStreamRequest(callback, metadata, deadline) { + var stream = client.makeRequest(this.channel, method, serialize, + deserialize, metadata, deadline); + var obj_stream = new ClientWritableObjectStream(stream); + stream.on('data', function forwardData(chunk) { + try { + callback(null, chunk); + } catch (e) { + callback(e); + } + }); + stream.on('status', function forwardStatus(status) { + if (status.code !== client.status.OK) { + callback(status); + } + }); + return obj_stream; + } + return makeClientStreamRequest; +} + +/** + * Get a function that can make server stream requests to the specified method. + * @param {string} method The name of the method to request + * @param {function(*):Buffer} serialize The serialization function for inputs + * @param {function(Buffer)} deserialize The deserialization function for + * outputs + * @return {Function} makeServerStreamRequest + */ +function makeServerStreamRequestFunction(method, serialize, deserialize) { + /** + * Make a server stream request with this method on the given channel with the + * given argument, etc. + * @this {SurfaceClient} Client object. Must have a channel member. + * @param {*} argument The argument to the call. Should be serializable with + * serialize + * @param {array=} metadata Array of metadata key/value pairs to add to the + * call + * @param {(number|Date)=} deadline The deadline for processing this request. + * Defaults to infinite future + * @return {EventEmitter} An event emitter for stream related events + */ + function makeServerStreamRequest(argument, metadata, deadline) { + var stream = client.makeRequest(this.channel, method, serialize, + deserialize, metadata, deadline); + var obj_stream = new ClientReadableObjectStream(stream); + stream.write(argument); + stream.end(); + return obj_stream; + } + return makeServerStreamRequest; +} + +/** + * Get a function that can make bidirectional stream requests to the specified + * method. + * @param {string} method The name of the method to request + * @param {function(*):Buffer} serialize The serialization function for inputs + * @param {function(Buffer)} deserialize The deserialization function for + * outputs + * @return {Function} makeBidiStreamRequest + */ +function makeBidiStreamRequestFunction(method, serialize, deserialize) { + /** + * Make a bidirectional stream request with this method on the given channel. + * @this {SurfaceClient} Client object. Must have a channel member. + * @param {array=} metadata Array of metadata key/value pairs to add to the + * call + * @param {(number|Date)=} deadline The deadline for processing this request. + * Defaults to infinite future + * @return {EventEmitter} An event emitter for stream related events + */ + function makeBidiStreamRequest(metadata, deadline) { + return client.makeRequest(this.channel, method, serialize, + deserialize, metadata, deadline); + } + return makeBidiStreamRequest; +} + +/** + * Map with short names for each of the requester maker functions. Used in + * makeClientConstructor + */ +var requester_makers = { + unary: makeUnaryRequestFunction, + server_stream: makeServerStreamRequestFunction, + client_stream: makeClientStreamRequestFunction, + bidi: makeBidiStreamRequestFunction +} + +/** + * Creates a constructor for clients for the given service + * @param {ProtoBuf.Reflect.Service} service The service to generate a client + * for + * @return {function(string, Object)} New client constructor + */ +function makeClientConstructor(service) { + var prefix = '/' + common.fullyQualifiedName(service) + '/'; + /** + * Create a client with the given methods + * @constructor + * @param {string} address The address of the server to connect to + * @param {Object} options Options to pass to the underlying channel + */ + function SurfaceClient(address, options) { + this.channel = new client.Channel(address, options); + } + + _.each(service.children, function(method) { + var method_type; + if (method.requestStream) { + if (method.responseStream) { + method_type = 'bidi'; + } else { + method_type = 'client_stream'; + } + } else { + if (method.responseStream) { + method_type = 'server_stream'; + } else { + method_type = 'unary'; + } + } + SurfaceClient.prototype[decapitalize(method.name)] = + requester_makers[method_type]( + prefix + capitalize(method.name), + common.serializeCls(method.resolvedRequestType.build()), + common.deserializeCls(method.resolvedResponseType.build())); + }); + + SurfaceClient.service = service; + + return SurfaceClient; +} + +exports.makeClientConstructor = makeClientConstructor; + +/** + * See docs for client.status + */ +exports.status = client.status; +/** + * See docs for client.callError + */ +exports.callError = client.callError; diff --git a/src/node/src/surface_server.js b/src/node/src/surface_server.js new file mode 100644 index 0000000000..af23ec211c --- /dev/null +++ b/src/node/src/surface_server.js @@ -0,0 +1,333 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +var _ = require('underscore'); + +var capitalize = require('underscore.string/capitalize'); +var decapitalize = require('underscore.string/decapitalize'); + +var Server = require('./server.js'); + +var stream = require('stream'); + +var Readable = stream.Readable; +var Writable = stream.Writable; +var Duplex = stream.Duplex; +var util = require('util'); + +var common = require('./common.js'); + +util.inherits(ServerReadableObjectStream, Readable); + +/** + * Class for representing a gRPC client streaming call as a Node stream on the + * server side. Extends from stream.Readable. + * @constructor + * @param {stream} stream Underlying binary Duplex stream for the call + */ +function ServerReadableObjectStream(stream) { + var options = {objectMode: true}; + Readable.call(this, options); + this._stream = stream; + Object.defineProperty(this, 'cancelled', { + get: function() { return stream.cancelled; } + }); + var self = this; + this._stream.on('cancelled', function() { + self.emit('cancelled'); + }); + this._stream.on('data', function forwardData(chunk) { + if (!self.push(chunk)) { + self._stream.pause(); + } + }); + this._stream.on('end', function forwardEnd() { + self.push(null); + }); + this._stream.pause(); +} + +/** + * _read implementation for both types of streams that allow reading. + * @this {ServerReadableObjectStream|ServerBidiObjectStream} + * @param {number} size Ignored + */ +function _read(size) { + this._stream.resume(); +} + +/** + * See docs for _read + */ +ServerReadableObjectStream.prototype._read = _read; + +util.inherits(ServerWritableObjectStream, Writable); + +/** + * Class for representing a gRPC server streaming call as a Node stream on the + * server side. Extends from stream.Writable. + * @constructor + * @param {stream} stream Underlying binary Duplex stream for the call + */ +function ServerWritableObjectStream(stream) { + var options = {objectMode: true}; + Writable.call(this, options); + this._stream = stream; + this._stream.on('cancelled', function() { + self.emit('cancelled'); + }); + this.on('finish', function() { + this._stream.end(); + }); +} + +/** + * _write implementation for both types of streams that allow writing + * @this {ServerWritableObjectStream} + * @param {*} chunk The value to write to the stream + * @param {string} encoding Ignored + * @param {function(Error)} callback Callback to call when finished writing + */ +function _write(chunk, encoding, callback) { + this._stream.write(chunk, encoding, callback); +} + +/** + * See docs for _write + */ +ServerWritableObjectStream.prototype._write = _write; + +/** + * Creates a binary stream handler function from a unary handler function + * @param {function(Object, function(Error, *))} handler Unary call handler + * @return {function(stream)} Binary stream handler + */ +function makeUnaryHandler(handler) { + /** + * Handles a stream by reading a single data value, passing it to the handler, + * and writing the response back to the stream. + * @param {stream} stream Binary data stream + */ + return function handleUnaryCall(stream) { + stream.on('data', function handleUnaryData(value) { + var call = {request: value}; + Object.defineProperty(call, 'cancelled', { + get: function() { return stream.cancelled;} + }); + stream.on('cancelled', function() { + call.emit('cancelled'); + }); + handler(call, function sendUnaryData(err, value) { + if (err) { + stream.emit('error', err); + } else { + stream.write(value); + stream.end(); + } + }); + }); + }; +} + +/** + * Creates a binary stream handler function from a client stream handler + * function + * @param {function(Readable, function(Error, *))} handler Client stream call + * handler + * @return {function(stream)} Binary stream handler + */ +function makeClientStreamHandler(handler) { + /** + * Handles a stream by passing a deserializing stream to the handler and + * writing the response back to the stream. + * @param {stream} stream Binary data stream + */ + return function handleClientStreamCall(stream) { + var object_stream = new ServerReadableObjectStream(stream); + handler(object_stream, function sendClientStreamData(err, value) { + if (err) { + stream.emit('error', err); + } else { + stream.write(value); + stream.end(); + } + }); + }; +} + +/** + * Creates a binary stream handler function from a server stream handler + * function + * @param {function(Writable)} handler Server stream call handler + * @return {function(stream)} Binary stream handler + */ +function makeServerStreamHandler(handler) { + /** + * Handles a stream by attaching it to a serializing stream, and passing it to + * the handler. + * @param {stream} stream Binary data stream + */ + return function handleServerStreamCall(stream) { + stream.on('data', function handleClientData(value) { + var object_stream = new ServerWritableObjectStream(stream); + object_stream.request = value; + handler(object_stream); + }); + }; +} + +/** + * Creates a binary stream handler function from a bidi stream handler function + * @param {function(Duplex)} handler Unary call handler + * @return {function(stream)} Binary stream handler + */ +function makeBidiStreamHandler(handler) { + return handler; +} + +/** + * Map with short names for each of the handler maker functions. Used in + * makeServerConstructor + */ +var handler_makers = { + unary: makeUnaryHandler, + server_stream: makeServerStreamHandler, + client_stream: makeClientStreamHandler, + bidi: makeBidiStreamHandler +}; + +/** + * Creates a constructor for servers with a service defined by the methods + * object. The methods object has string keys and values of this form: + * {serialize: function, deserialize: function, client_stream: bool, + * server_stream: bool} + * @param {Object} methods Method descriptor for each method the server should + * expose + * @param {string} prefix The prefex to prepend to each method name + * @return {function(Object, Object)} New server constructor + */ +function makeServerConstructor(services) { + var qual_names = []; + _.each(services, function(service) { + _.each(service.children, function(method) { + var name = common.fullyQualifiedName(method); + if (_.indexOf(qual_names, name) !== -1) { + throw new Error('Method ' + name + ' exposed by more than one service'); + } + qual_names.push(name); + }); + }); + /** + * Create a server with the given handlers for all of the methods. + * @constructor + * @param {Object} service_handlers Map from service names to map from method + * names to handlers + * @param {Object} options Options to pass to the underlying server + */ + function SurfaceServer(service_handlers, options) { + var server = new Server(options); + this.inner_server = server; + _.each(services, function(service) { + var service_name = common.fullyQualifiedName(service); + if (service_handlers[service_name] === undefined) { + throw new Error('Handlers for service ' + + service_name + ' not provided.'); + } + var prefix = '/' + common.fullyQualifiedName(service) + '/'; + _.each(service.children, function(method) { + var method_type; + if (method.requestStream) { + if (method.responseStream) { + method_type = 'bidi'; + } else { + method_type = 'client_stream'; + } + } else { + if (method.responseStream) { + method_type = 'server_stream'; + } else { + method_type = 'unary'; + } + } + if (service_handlers[service_name][decapitalize(method.name)] === + undefined) { + throw new Error('Method handler for ' + + common.fullyQualifiedName(method) + ' not provided.'); + } + var binary_handler = handler_makers[method_type]( + service_handlers[service_name][decapitalize(method.name)]); + var serialize = common.serializeCls( + method.resolvedResponseType.build()); + var deserialize = common.deserializeCls( + method.resolvedRequestType.build()); + server.register(prefix + capitalize(method.name), binary_handler, + serialize, deserialize); + }); + }, this); + } + + /** + * Binds the server to the given port, with SSL enabled if secure is specified + * @param {string} port The port that the server should bind on, in the format + * "address:port" + * @param {boolean=} secure Whether the server should open a secure port + * @return {SurfaceServer} this + */ + SurfaceServer.prototype.bind = function(port, secure) { + return this.inner_server.bind(port, secure); + }; + + /** + * Starts the server listening on any bound ports + * @return {SurfaceServer} this + */ + SurfaceServer.prototype.listen = function() { + this.inner_server.start(); + return this; + }; + + /** + * Shuts the server down; tells it to stop listening for new requests and to + * kill old requests. + */ + SurfaceServer.prototype.shutdown = function() { + this.inner_server.shutdown(); + }; + + return SurfaceServer; +} + +/** + * See documentation for makeServerConstructor + */ +exports.makeServerConstructor = makeServerConstructor; diff --git a/src/node/surface_client.js b/src/node/surface_client.js deleted file mode 100644 index 16c31809f4..0000000000 --- a/src/node/surface_client.js +++ /dev/null @@ -1,357 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -var _ = require('underscore'); - -var capitalize = require('underscore.string/capitalize'); -var decapitalize = require('underscore.string/decapitalize'); - -var client = require('./client.js'); - -var common = require('./common.js'); - -var EventEmitter = require('events').EventEmitter; - -var stream = require('stream'); - -var Readable = stream.Readable; -var Writable = stream.Writable; -var Duplex = stream.Duplex; -var util = require('util'); - - -function forwardEvent(fromEmitter, toEmitter, event) { - fromEmitter.on(event, function forward() { - _.partial(toEmitter.emit, event).apply(toEmitter, arguments); - }); -} - -util.inherits(ClientReadableObjectStream, Readable); - -/** - * Class for representing a gRPC server streaming call as a Node stream on the - * client side. Extends from stream.Readable. - * @constructor - * @param {stream} stream Underlying binary Duplex stream for the call - */ -function ClientReadableObjectStream(stream) { - var options = {objectMode: true}; - Readable.call(this, options); - this._stream = stream; - var self = this; - forwardEvent(stream, this, 'status'); - forwardEvent(stream, this, 'metadata'); - this._stream.on('data', function forwardData(chunk) { - if (!self.push(chunk)) { - self._stream.pause(); - } - }); - this._stream.pause(); -} - -/** - * _read implementation for both types of streams that allow reading. - * @this {ClientReadableObjectStream} - * @param {number} size Ignored - */ -function _read(size) { - this._stream.resume(); -} - -/** - * See docs for _read - */ -ClientReadableObjectStream.prototype._read = _read; - -util.inherits(ClientWritableObjectStream, Writable); - -/** - * Class for representing a gRPC client streaming call as a Node stream on the - * client side. Extends from stream.Writable. - * @constructor - * @param {stream} stream Underlying binary Duplex stream for the call - */ -function ClientWritableObjectStream(stream) { - var options = {objectMode: true}; - Writable.call(this, options); - this._stream = stream; - forwardEvent(stream, this, 'status'); - forwardEvent(stream, this, 'metadata'); - this.on('finish', function() { - this._stream.end(); - }); -} - -/** - * _write implementation for both types of streams that allow writing - * @this {ClientWritableObjectStream} - * @param {*} chunk The value to write to the stream - * @param {string} encoding Ignored - * @param {function(Error)} callback Callback to call when finished writing - */ -function _write(chunk, encoding, callback) { - this._stream.write(chunk, encoding, callback); -} - -/** - * See docs for _write - */ -ClientWritableObjectStream.prototype._write = _write; - -/** - * Cancel the underlying call - */ -function cancel() { - this._stream.cancel(); -} - -ClientReadableObjectStream.prototype.cancel = cancel; -ClientWritableObjectStream.prototype.cancel = cancel; - -/** - * 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 - * @param {function(Buffer)} deserialize The deserialization function for - * outputs - * @return {Function} makeUnaryRequest - */ -function makeUnaryRequestFunction(method, serialize, deserialize) { - /** - * Make a unary request with this method on the given channel with the given - * argument, callback, etc. - * @this {SurfaceClient} Client object. Must have a channel member. - * @param {*} argument The argument to the call. Should be serializable with - * serialize - * @param {function(?Error, value=)} callback The callback to for when the - * response is received - * @param {array=} metadata Array of metadata key/value pairs to add to the - * call - * @param {(number|Date)=} deadline The deadline for processing this request. - * Defaults to infinite future - * @return {EventEmitter} An event emitter for stream related events - */ - function makeUnaryRequest(argument, callback, metadata, deadline) { - var stream = client.makeRequest(this.channel, method, serialize, - deserialize, metadata, deadline); - var emitter = new EventEmitter(); - emitter.cancel = function cancel() { - stream.cancel(); - }; - forwardEvent(stream, emitter, 'status'); - forwardEvent(stream, emitter, 'metadata'); - stream.write(argument); - stream.end(); - stream.on('data', function forwardData(chunk) { - try { - callback(null, chunk); - } catch (e) { - callback(e); - } - }); - stream.on('status', function forwardStatus(status) { - if (status.code !== client.status.OK) { - callback(status); - } - }); - return emitter; - } - return makeUnaryRequest; -} - -/** - * Get a function that can make client stream requests to the specified method. - * @param {string} method The name of the method to request - * @param {function(*):Buffer} serialize The serialization function for inputs - * @param {function(Buffer)} deserialize The deserialization function for - * outputs - * @return {Function} makeClientStreamRequest - */ -function makeClientStreamRequestFunction(method, serialize, deserialize) { - /** - * Make a client stream request with this method on the given channel with the - * given callback, etc. - * @this {SurfaceClient} Client object. Must have a channel member. - * @param {function(?Error, value=)} callback The callback to for when the - * response is received - * @param {array=} metadata Array of metadata key/value pairs to add to the - * call - * @param {(number|Date)=} deadline The deadline for processing this request. - * Defaults to infinite future - * @return {EventEmitter} An event emitter for stream related events - */ - function makeClientStreamRequest(callback, metadata, deadline) { - var stream = client.makeRequest(this.channel, method, serialize, - deserialize, metadata, deadline); - var obj_stream = new ClientWritableObjectStream(stream); - stream.on('data', function forwardData(chunk) { - try { - callback(null, chunk); - } catch (e) { - callback(e); - } - }); - stream.on('status', function forwardStatus(status) { - if (status.code !== client.status.OK) { - callback(status); - } - }); - return obj_stream; - } - return makeClientStreamRequest; -} - -/** - * Get a function that can make server stream requests to the specified method. - * @param {string} method The name of the method to request - * @param {function(*):Buffer} serialize The serialization function for inputs - * @param {function(Buffer)} deserialize The deserialization function for - * outputs - * @return {Function} makeServerStreamRequest - */ -function makeServerStreamRequestFunction(method, serialize, deserialize) { - /** - * Make a server stream request with this method on the given channel with the - * given argument, etc. - * @this {SurfaceClient} Client object. Must have a channel member. - * @param {*} argument The argument to the call. Should be serializable with - * serialize - * @param {array=} metadata Array of metadata key/value pairs to add to the - * call - * @param {(number|Date)=} deadline The deadline for processing this request. - * Defaults to infinite future - * @return {EventEmitter} An event emitter for stream related events - */ - function makeServerStreamRequest(argument, metadata, deadline) { - var stream = client.makeRequest(this.channel, method, serialize, - deserialize, metadata, deadline); - var obj_stream = new ClientReadableObjectStream(stream); - stream.write(argument); - stream.end(); - return obj_stream; - } - return makeServerStreamRequest; -} - -/** - * Get a function that can make bidirectional stream requests to the specified - * method. - * @param {string} method The name of the method to request - * @param {function(*):Buffer} serialize The serialization function for inputs - * @param {function(Buffer)} deserialize The deserialization function for - * outputs - * @return {Function} makeBidiStreamRequest - */ -function makeBidiStreamRequestFunction(method, serialize, deserialize) { - /** - * Make a bidirectional stream request with this method on the given channel. - * @this {SurfaceClient} Client object. Must have a channel member. - * @param {array=} metadata Array of metadata key/value pairs to add to the - * call - * @param {(number|Date)=} deadline The deadline for processing this request. - * Defaults to infinite future - * @return {EventEmitter} An event emitter for stream related events - */ - function makeBidiStreamRequest(metadata, deadline) { - return client.makeRequest(this.channel, method, serialize, - deserialize, metadata, deadline); - } - return makeBidiStreamRequest; -} - -/** - * Map with short names for each of the requester maker functions. Used in - * makeClientConstructor - */ -var requester_makers = { - unary: makeUnaryRequestFunction, - server_stream: makeServerStreamRequestFunction, - client_stream: makeClientStreamRequestFunction, - bidi: makeBidiStreamRequestFunction -} - -/** - * Creates a constructor for clients for the given service - * @param {ProtoBuf.Reflect.Service} service The service to generate a client - * for - * @return {function(string, Object)} New client constructor - */ -function makeClientConstructor(service) { - var prefix = '/' + common.fullyQualifiedName(service) + '/'; - /** - * Create a client with the given methods - * @constructor - * @param {string} address The address of the server to connect to - * @param {Object} options Options to pass to the underlying channel - */ - function SurfaceClient(address, options) { - this.channel = new client.Channel(address, options); - } - - _.each(service.children, function(method) { - var method_type; - if (method.requestStream) { - if (method.responseStream) { - method_type = 'bidi'; - } else { - method_type = 'client_stream'; - } - } else { - if (method.responseStream) { - method_type = 'server_stream'; - } else { - method_type = 'unary'; - } - } - SurfaceClient.prototype[decapitalize(method.name)] = - requester_makers[method_type]( - prefix + capitalize(method.name), - common.serializeCls(method.resolvedRequestType.build()), - common.deserializeCls(method.resolvedResponseType.build())); - }); - - SurfaceClient.service = service; - - return SurfaceClient; -} - -exports.makeClientConstructor = makeClientConstructor; - -/** - * See docs for client.status - */ -exports.status = client.status; -/** - * See docs for client.callError - */ -exports.callError = client.callError; diff --git a/src/node/surface_server.js b/src/node/surface_server.js deleted file mode 100644 index af23ec211c..0000000000 --- a/src/node/surface_server.js +++ /dev/null @@ -1,333 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -var _ = require('underscore'); - -var capitalize = require('underscore.string/capitalize'); -var decapitalize = require('underscore.string/decapitalize'); - -var Server = require('./server.js'); - -var stream = require('stream'); - -var Readable = stream.Readable; -var Writable = stream.Writable; -var Duplex = stream.Duplex; -var util = require('util'); - -var common = require('./common.js'); - -util.inherits(ServerReadableObjectStream, Readable); - -/** - * Class for representing a gRPC client streaming call as a Node stream on the - * server side. Extends from stream.Readable. - * @constructor - * @param {stream} stream Underlying binary Duplex stream for the call - */ -function ServerReadableObjectStream(stream) { - var options = {objectMode: true}; - Readable.call(this, options); - this._stream = stream; - Object.defineProperty(this, 'cancelled', { - get: function() { return stream.cancelled; } - }); - var self = this; - this._stream.on('cancelled', function() { - self.emit('cancelled'); - }); - this._stream.on('data', function forwardData(chunk) { - if (!self.push(chunk)) { - self._stream.pause(); - } - }); - this._stream.on('end', function forwardEnd() { - self.push(null); - }); - this._stream.pause(); -} - -/** - * _read implementation for both types of streams that allow reading. - * @this {ServerReadableObjectStream|ServerBidiObjectStream} - * @param {number} size Ignored - */ -function _read(size) { - this._stream.resume(); -} - -/** - * See docs for _read - */ -ServerReadableObjectStream.prototype._read = _read; - -util.inherits(ServerWritableObjectStream, Writable); - -/** - * Class for representing a gRPC server streaming call as a Node stream on the - * server side. Extends from stream.Writable. - * @constructor - * @param {stream} stream Underlying binary Duplex stream for the call - */ -function ServerWritableObjectStream(stream) { - var options = {objectMode: true}; - Writable.call(this, options); - this._stream = stream; - this._stream.on('cancelled', function() { - self.emit('cancelled'); - }); - this.on('finish', function() { - this._stream.end(); - }); -} - -/** - * _write implementation for both types of streams that allow writing - * @this {ServerWritableObjectStream} - * @param {*} chunk The value to write to the stream - * @param {string} encoding Ignored - * @param {function(Error)} callback Callback to call when finished writing - */ -function _write(chunk, encoding, callback) { - this._stream.write(chunk, encoding, callback); -} - -/** - * See docs for _write - */ -ServerWritableObjectStream.prototype._write = _write; - -/** - * Creates a binary stream handler function from a unary handler function - * @param {function(Object, function(Error, *))} handler Unary call handler - * @return {function(stream)} Binary stream handler - */ -function makeUnaryHandler(handler) { - /** - * Handles a stream by reading a single data value, passing it to the handler, - * and writing the response back to the stream. - * @param {stream} stream Binary data stream - */ - return function handleUnaryCall(stream) { - stream.on('data', function handleUnaryData(value) { - var call = {request: value}; - Object.defineProperty(call, 'cancelled', { - get: function() { return stream.cancelled;} - }); - stream.on('cancelled', function() { - call.emit('cancelled'); - }); - handler(call, function sendUnaryData(err, value) { - if (err) { - stream.emit('error', err); - } else { - stream.write(value); - stream.end(); - } - }); - }); - }; -} - -/** - * Creates a binary stream handler function from a client stream handler - * function - * @param {function(Readable, function(Error, *))} handler Client stream call - * handler - * @return {function(stream)} Binary stream handler - */ -function makeClientStreamHandler(handler) { - /** - * Handles a stream by passing a deserializing stream to the handler and - * writing the response back to the stream. - * @param {stream} stream Binary data stream - */ - return function handleClientStreamCall(stream) { - var object_stream = new ServerReadableObjectStream(stream); - handler(object_stream, function sendClientStreamData(err, value) { - if (err) { - stream.emit('error', err); - } else { - stream.write(value); - stream.end(); - } - }); - }; -} - -/** - * Creates a binary stream handler function from a server stream handler - * function - * @param {function(Writable)} handler Server stream call handler - * @return {function(stream)} Binary stream handler - */ -function makeServerStreamHandler(handler) { - /** - * Handles a stream by attaching it to a serializing stream, and passing it to - * the handler. - * @param {stream} stream Binary data stream - */ - return function handleServerStreamCall(stream) { - stream.on('data', function handleClientData(value) { - var object_stream = new ServerWritableObjectStream(stream); - object_stream.request = value; - handler(object_stream); - }); - }; -} - -/** - * Creates a binary stream handler function from a bidi stream handler function - * @param {function(Duplex)} handler Unary call handler - * @return {function(stream)} Binary stream handler - */ -function makeBidiStreamHandler(handler) { - return handler; -} - -/** - * Map with short names for each of the handler maker functions. Used in - * makeServerConstructor - */ -var handler_makers = { - unary: makeUnaryHandler, - server_stream: makeServerStreamHandler, - client_stream: makeClientStreamHandler, - bidi: makeBidiStreamHandler -}; - -/** - * Creates a constructor for servers with a service defined by the methods - * object. The methods object has string keys and values of this form: - * {serialize: function, deserialize: function, client_stream: bool, - * server_stream: bool} - * @param {Object} methods Method descriptor for each method the server should - * expose - * @param {string} prefix The prefex to prepend to each method name - * @return {function(Object, Object)} New server constructor - */ -function makeServerConstructor(services) { - var qual_names = []; - _.each(services, function(service) { - _.each(service.children, function(method) { - var name = common.fullyQualifiedName(method); - if (_.indexOf(qual_names, name) !== -1) { - throw new Error('Method ' + name + ' exposed by more than one service'); - } - qual_names.push(name); - }); - }); - /** - * Create a server with the given handlers for all of the methods. - * @constructor - * @param {Object} service_handlers Map from service names to map from method - * names to handlers - * @param {Object} options Options to pass to the underlying server - */ - function SurfaceServer(service_handlers, options) { - var server = new Server(options); - this.inner_server = server; - _.each(services, function(service) { - var service_name = common.fullyQualifiedName(service); - if (service_handlers[service_name] === undefined) { - throw new Error('Handlers for service ' + - service_name + ' not provided.'); - } - var prefix = '/' + common.fullyQualifiedName(service) + '/'; - _.each(service.children, function(method) { - var method_type; - if (method.requestStream) { - if (method.responseStream) { - method_type = 'bidi'; - } else { - method_type = 'client_stream'; - } - } else { - if (method.responseStream) { - method_type = 'server_stream'; - } else { - method_type = 'unary'; - } - } - if (service_handlers[service_name][decapitalize(method.name)] === - undefined) { - throw new Error('Method handler for ' + - common.fullyQualifiedName(method) + ' not provided.'); - } - var binary_handler = handler_makers[method_type]( - service_handlers[service_name][decapitalize(method.name)]); - var serialize = common.serializeCls( - method.resolvedResponseType.build()); - var deserialize = common.deserializeCls( - method.resolvedRequestType.build()); - server.register(prefix + capitalize(method.name), binary_handler, - serialize, deserialize); - }); - }, this); - } - - /** - * Binds the server to the given port, with SSL enabled if secure is specified - * @param {string} port The port that the server should bind on, in the format - * "address:port" - * @param {boolean=} secure Whether the server should open a secure port - * @return {SurfaceServer} this - */ - SurfaceServer.prototype.bind = function(port, secure) { - return this.inner_server.bind(port, secure); - }; - - /** - * Starts the server listening on any bound ports - * @return {SurfaceServer} this - */ - SurfaceServer.prototype.listen = function() { - this.inner_server.start(); - return this; - }; - - /** - * Shuts the server down; tells it to stop listening for new requests and to - * kill old requests. - */ - SurfaceServer.prototype.shutdown = function() { - this.inner_server.shutdown(); - }; - - return SurfaceServer; -} - -/** - * See documentation for makeServerConstructor - */ -exports.makeServerConstructor = makeServerConstructor; diff --git a/src/node/tag.cc b/src/node/tag.cc deleted file mode 100644 index dc8e523e12..0000000000 --- a/src/node/tag.cc +++ /dev/null @@ -1,101 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include -#include "tag.h" - -namespace grpc { -namespace node { - -using v8::Handle; -using v8::HandleScope; -using v8::Persistent; -using v8::Value; - -struct tag { - tag(Persistent *tag, Persistent *call) - : persist_tag(tag), persist_call(call) {} - - ~tag() { - persist_tag->Dispose(); - if (persist_call != NULL) { - persist_call->Dispose(); - } - } - Persistent *persist_tag; - Persistent *persist_call; -}; - -void *CreateTag(Handle tag, Handle call) { - NanScope(); - Persistent *persist_tag = new Persistent(); - NanAssignPersistent(*persist_tag, tag); - Persistent *persist_call; - if (call->IsNull() || call->IsUndefined()) { - persist_call = NULL; - } else { - persist_call = new Persistent(); - NanAssignPersistent(*persist_call, call); - } - struct tag *tag_struct = new struct tag(persist_tag, persist_call); - return reinterpret_cast(tag_struct); -} - -Handle GetTagHandle(void *tag) { - NanEscapableScope(); - struct tag *tag_struct = reinterpret_cast(tag); - Handle tag_value = NanNew(*tag_struct->persist_tag); - return NanEscapeScope(tag_value); -} - -bool TagHasCall(void *tag) { - struct tag *tag_struct = reinterpret_cast(tag); - return tag_struct->persist_call != NULL; -} - -Handle TagGetCall(void *tag) { - NanEscapableScope(); - struct tag *tag_struct = reinterpret_cast(tag); - if (tag_struct->persist_call == NULL) { - return NanEscapeScope(NanNull()); - } - Handle call_value = NanNew(*tag_struct->persist_call); - return NanEscapeScope(call_value); -} - -void DestroyTag(void *tag) { delete reinterpret_cast(tag); } - -} // namespace node -} // namespace grpc diff --git a/src/node/tag.h b/src/node/tag.h deleted file mode 100644 index bdb09252d9..0000000000 --- a/src/node/tag.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef NET_GRPC_NODE_TAG_H_ -#define NET_GRPC_NODE_TAG_H_ - -#include - -namespace grpc { -namespace node { - -/* Create a void* tag that can be passed to various grpc_call functions from - a javascript value and the javascript wrapper for the call. The call can be - null. */ -void *CreateTag(v8::Handle tag, v8::Handle call); -/* Return the javascript value stored in the tag */ -v8::Handle GetTagHandle(void *tag); -/* Returns true if the call was set (non-null) when the tag was created */ -bool TagHasCall(void *tag); -/* Returns the javascript wrapper for the call associated with this tag */ -v8::Handle TagGetCall(void *call); -/* Destroy the tag and all resources it is holding. It is illegal to call any - of these other functions on a tag after it has been destroyed. */ -void DestroyTag(void *tag); - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_TAG_H_ diff --git a/src/node/timeval.cc b/src/node/timeval.cc deleted file mode 100644 index 687e33576b..0000000000 --- a/src/node/timeval.cc +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#include "grpc/grpc.h" -#include "grpc/support/time.h" -#include "timeval.h" - -namespace grpc { -namespace node { - -gpr_timespec MillisecondsToTimespec(double millis) { - if (millis == std::numeric_limits::infinity()) { - return gpr_inf_future; - } else if (millis == -std::numeric_limits::infinity()) { - return gpr_inf_past; - } else { - return gpr_time_from_micros(static_cast(millis * 1000)); - } -} - -double TimespecToMilliseconds(gpr_timespec timespec) { - if (gpr_time_cmp(timespec, gpr_inf_future) == 0) { - return std::numeric_limits::infinity(); - } else if (gpr_time_cmp(timespec, gpr_inf_past) == 0) { - return -std::numeric_limits::infinity(); - } else { - struct timeval time = gpr_timeval_from_timespec(timespec); - return (static_cast(time.tv_sec) * 1000 + - static_cast(time.tv_usec) / 1000); - } -} - -} // namespace node -} // namespace grpc diff --git a/src/node/timeval.h b/src/node/timeval.h deleted file mode 100644 index 1fb0f2c690..0000000000 --- a/src/node/timeval.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef NET_GRPC_NODE_TIMEVAL_H_ -#define NET_GRPC_NODE_TIMEVAL_H_ - -#include "grpc/support/time.h" - -namespace grpc { -namespace node { - -double TimespecToMilliseconds(gpr_timespec time); -gpr_timespec MillisecondsToTimespec(double millis); - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_TIMEVAL_H_ -- cgit v1.2.3 From 9df2693744a69a3f239f21e4e6e94d643289cd94 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 26 Jan 2015 17:17:59 -0800 Subject: Fixed file references to match moved files --- src/node/binding.gyp | 22 +++++++++++----------- src/node/index.js | 4 ++-- src/node/package.json | 2 +- src/node/test/client_server_test.js | 6 +++--- src/node/test/server_test.js | 2 +- src/node/test/surface_test.js | 4 ++-- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/node/binding.gyp b/src/node/binding.gyp index fe4b5da9c8..cf2a6acb04 100644 --- a/src/node/binding.gyp +++ b/src/node/binding.gyp @@ -28,17 +28,17 @@ }, "target_name": "grpc", "sources": [ - "byte_buffer.cc", - "call.cc", - "channel.cc", - "completion_queue_async_worker.cc", - "credentials.cc", - "event.cc", - "node_grpc.cc", - "server.cc", - "server_credentials.cc", - "tag.cc", - "timeval.cc" + "ext/byte_buffer.cc", + "ext/call.cc", + "ext/channel.cc", + "ext/completion_queue_async_worker.cc", + "ext/credentials.cc", + "ext/event.cc", + "ext/node_grpc.cc", + "ext/server.cc", + "ext/server_credentials.cc", + "ext/tag.cc", + "ext/timeval.cc" ], 'conditions' : [ ['no_install=="yes"', { diff --git a/src/node/index.js b/src/node/index.js index 751c3525d3..0627e7f557 100644 --- a/src/node/index.js +++ b/src/node/index.js @@ -35,9 +35,9 @@ var _ = require('underscore'); var ProtoBuf = require('protobufjs'); -var surface_client = require('./surface_client.js'); +var surface_client = require('./src/surface_client.js'); -var surface_server = require('./surface_server.js'); +var surface_server = require('./src/surface_server.js'); var grpc = require('bindings')('grpc'); diff --git a/src/node/package.json b/src/node/package.json index 5f3c6fa345..8a0b51dda8 100644 --- a/src/node/package.json +++ b/src/node/package.json @@ -17,5 +17,5 @@ "mocha": "~1.21.0", "minimist": "^1.1.0" }, - "main": "main.js" + "main": "index.js" } diff --git a/src/node/test/client_server_test.js b/src/node/test/client_server_test.js index 11cc511dc9..d657ef41a4 100644 --- a/src/node/test/client_server_test.js +++ b/src/node/test/client_server_test.js @@ -35,9 +35,9 @@ var assert = require('assert'); var fs = require('fs'); var path = require('path'); var grpc = require('bindings')('grpc.node'); -var Server = require('../server'); -var client = require('../client'); -var common = require('../common'); +var Server = require('../src/server'); +var client = require('../src/client'); +var common = require('../src/common'); var _ = require('highland'); var ca_path = path.join(__dirname, 'data/ca.pem'); diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js index d0ec1555c6..5fad9a5564 100644 --- a/src/node/test/server_test.js +++ b/src/node/test/server_test.js @@ -33,7 +33,7 @@ var assert = require('assert'); var grpc = require('bindings')('grpc.node'); -var Server = require('../server'); +var Server = require('../src/server'); /** * This is used for testing functions with multiple asynchronous calls that diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js index 16e4869d83..85f4841d4b 100644 --- a/src/node/test/surface_test.js +++ b/src/node/test/surface_test.js @@ -33,9 +33,9 @@ var assert = require('assert'); -var surface_server = require('../surface_server.js'); +var surface_server = require('../src/surface_server.js'); -var surface_client = require('../surface_client.js'); +var surface_client = require('../src/surface_client.js'); var ProtoBuf = require('protobufjs'); -- cgit v1.2.3 From a679f9fbd030c63516e884bce1681a88ed0a641e Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 18:24:32 -0800 Subject: Removed port_picker form client_stub_spec --- src/ruby/spec/generic/client_stub_spec.rb | 144 ++++++++++++++++-------------- 1 file changed, 78 insertions(+), 66 deletions(-) diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb index 8ebe48bc4c..1f9c9857b3 100644 --- a/src/ruby/spec/generic/client_stub_spec.rb +++ b/src/ruby/spec/generic/client_stub_spec.rb @@ -29,9 +29,9 @@ require 'grpc' require 'xray/thread_dump_signal_handler' -require_relative '../port_picker' NOOP = proc { |x| x } +FAKE_HOST = 'localhost:50505' def wakey_thread(&blk) awake_mutex, awake_cond = Mutex.new, ConditionVariable.new @@ -67,7 +67,7 @@ describe 'ClientStub' do describe '#new' do it 'can be created from a host and args' do - host = new_test_host + host = FAKE_HOST opts = { a_channel_arg: 'an_arg' } blk = proc do GRPC::ClientStub.new(host, @cq, **opts) @@ -76,7 +76,7 @@ describe 'ClientStub' do end it 'can be created with a default deadline' do - host = new_test_host + host = FAKE_HOST opts = { a_channel_arg: 'an_arg', deadline: 5 } blk = proc do GRPC::ClientStub.new(host, @cq, **opts) @@ -85,7 +85,7 @@ describe 'ClientStub' do end it 'can be created with an channel override' do - host = new_test_host + host = FAKE_HOST opts = { a_channel_arg: 'an_arg', channel_override: @ch } blk = proc do GRPC::ClientStub.new(host, @cq, **opts) @@ -94,7 +94,7 @@ describe 'ClientStub' do end it 'cannot be created with a bad channel override' do - host = new_test_host + host = FAKE_HOST blk = proc do opts = { a_channel_arg: 'an_arg', channel_override: Object.new } GRPC::ClientStub.new(host, @cq, **opts) @@ -103,7 +103,7 @@ describe 'ClientStub' do end it 'cannot be created with bad credentials' do - host = new_test_host + host = FAKE_HOST blk = proc do opts = { a_channel_arg: 'an_arg', creds: Object.new } GRPC::ClientStub.new(host, @cq, **opts) @@ -113,7 +113,7 @@ describe 'ClientStub' do it 'can be created with test test credentials' do certs = load_test_certs - host = new_test_host + host = FAKE_HOST blk = proc do opts = { GRPC::Core::Channel::SSL_TARGET => 'foo.test.google.com', @@ -133,16 +133,17 @@ describe 'ClientStub' do shared_examples 'request response' do it 'should send a request to/receive a reply from a server' do - host = new_test_host - th = run_request_response(host, @sent_msg, @resp, @pass) - stub = GRPC::ClientStub.new(host, @cq) + server_port = create_test_server + th = run_request_response(@sent_msg, @resp, @pass) + stub = GRPC::ClientStub.new("localhost:#{server_port}", @cq) expect(get_response(stub)).to eq(@resp) th.join end it 'should send metadata to the server ok' do - host = new_test_host - th = run_request_response(host, @sent_msg, @resp, @pass, + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_request_response(@sent_msg, @resp, @pass, k1: 'v1', k2: 'v2') stub = GRPC::ClientStub.new(host, @cq) expect(get_response(stub)).to eq(@resp) @@ -150,8 +151,9 @@ describe 'ClientStub' do end it 'should update the sent metadata with a provided metadata updater' do - host = new_test_host - th = run_request_response(host, @sent_msg, @resp, @pass, + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_request_response(@sent_msg, @resp, @pass, k1: 'updated-v1', k2: 'v2') update_md = proc do |md| md[:k1] = 'updated-v1' @@ -163,8 +165,9 @@ describe 'ClientStub' do end it 'should send a request when configured using an override channel' do - alt_host = new_test_host - th = run_request_response(alt_host, @sent_msg, @resp, @pass) + server_port = create_test_server + alt_host = "localhost:#{server_port}" + th = run_request_response(@sent_msg, @resp, @pass) ch = GRPC::Core::Channel.new(alt_host, nil) stub = GRPC::ClientStub.new('ignored-host', @cq, channel_override: ch) expect(get_response(stub)).to eq(@resp) @@ -172,8 +175,9 @@ describe 'ClientStub' do end it 'should raise an error if the status is not OK' do - host = new_test_host - th = run_request_response(host, @sent_msg, @resp, @fail) + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_request_response(@sent_msg, @resp, @fail) stub = GRPC::ClientStub.new(host, @cq) blk = proc { get_response(stub) } expect(&blk).to raise_error(GRPC::BadStatus) @@ -210,16 +214,18 @@ describe 'ClientStub' do end it 'should send requests to/receive a reply from a server' do - host = new_test_host - th = run_client_streamer(host, @sent_msgs, @resp, @pass) + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_client_streamer(@sent_msgs, @resp, @pass) stub = GRPC::ClientStub.new(host, @cq) expect(get_response(stub)).to eq(@resp) th.join end it 'should send metadata to the server ok' do - host = new_test_host - th = run_client_streamer(host, @sent_msgs, @resp, @pass, + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_client_streamer(@sent_msgs, @resp, @pass, k1: 'v1', k2: 'v2') stub = GRPC::ClientStub.new(host, @cq) expect(get_response(stub)).to eq(@resp) @@ -227,8 +233,9 @@ describe 'ClientStub' do end it 'should update the sent metadata with a provided metadata updater' do - host = new_test_host - th = run_client_streamer(host, @sent_msgs, @resp, @pass, + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_client_streamer(@sent_msgs, @resp, @pass, k1: 'updated-v1', k2: 'v2') update_md = proc do |md| md[:k1] = 'updated-v1' @@ -240,8 +247,9 @@ describe 'ClientStub' do end it 'should raise an error if the status is not ok' do - host = new_test_host - th = run_client_streamer(host, @sent_msgs, @resp, @fail) + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_client_streamer(@sent_msgs, @resp, @fail) stub = GRPC::ClientStub.new(host, @cq) blk = proc { get_response(stub) } expect(&blk).to raise_error(GRPC::BadStatus) @@ -278,16 +286,18 @@ describe 'ClientStub' do end it 'should send a request to/receive replies from a server' do - host = new_test_host - th = run_server_streamer(host, @sent_msg, @replys, @pass) + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_server_streamer(@sent_msg, @replys, @pass) stub = GRPC::ClientStub.new(host, @cq) expect(get_responses(stub).collect { |r| r }).to eq(@replys) th.join end it 'should raise an error if the status is not ok' do - host = new_test_host - th = run_server_streamer(host, @sent_msg, @replys, @fail) + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_server_streamer(@sent_msg, @replys, @fail) stub = GRPC::ClientStub.new(host, @cq) e = get_responses(stub) expect { e.collect { |r| r } }.to raise_error(GRPC::BadStatus) @@ -295,8 +305,9 @@ describe 'ClientStub' do end it 'should send metadata to the server ok' do - host = new_test_host - th = run_server_streamer(host, @sent_msg, @replys, @fail, + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_server_streamer(@sent_msg, @replys, @fail, k1: 'v1', k2: 'v2') stub = GRPC::ClientStub.new(host, @cq) e = get_responses(stub) @@ -305,8 +316,9 @@ describe 'ClientStub' do end it 'should update the sent metadata with a provided metadata updater' do - host = new_test_host - th = run_server_streamer(host, @sent_msg, @replys, @pass, + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_server_streamer(@sent_msg, @replys, @pass, k1: 'updated-v1', k2: 'v2') update_md = proc do |md| md[:k1] = 'updated-v1' @@ -352,8 +364,9 @@ describe 'ClientStub' do end it 'supports sending all the requests first', bidi: true do - host = new_test_host - th = run_bidi_streamer_handle_inputs_first(host, @sent_msgs, @replys, + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_bidi_streamer_handle_inputs_first(@sent_msgs, @replys, @pass) stub = GRPC::ClientStub.new(host, @cq) e = get_responses(stub) @@ -362,8 +375,9 @@ describe 'ClientStub' do end it 'supports client-initiated ping pong', bidi: true do - host = new_test_host - th = run_bidi_streamer_echo_ping_pong(host, @sent_msgs, @pass, true) + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, true) stub = GRPC::ClientStub.new(host, @cq) e = get_responses(stub) expect(e.collect { |r| r }).to eq(@sent_msgs) @@ -377,8 +391,9 @@ describe 'ClientStub' do # they receive a message from the client. Without receiving all the # metadata, the server does not accept the call, so this test hangs. xit 'supports a server-initiated ping pong', bidi: true do - host = new_test_host - th = run_bidi_streamer_echo_ping_pong(host, @sent_msgs, @pass, false) + server_port = create_test_server + host = "localhost:#{server_port}" + th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, false) stub = GRPC::ClientStub.new(host, @cq) e = get_responses(stub) expect(e.collect { |r| r }).to eq(@sent_msgs) @@ -410,10 +425,10 @@ describe 'ClientStub' do end end - def run_server_streamer(hostname, expected_input, replys, status, **kw) + def run_server_streamer(expected_input, replys, status, **kw) wanted_metadata = kw.clone wakey_thread do |mtx, cnd| - c = expect_server_to_be_invoked(hostname, mtx, cnd) + c = expect_server_to_be_invoked(mtx, cnd) wanted_metadata.each do |k, v| expect(c.metadata[k.to_s]).to eq(v) end @@ -423,20 +438,19 @@ describe 'ClientStub' do end end - def run_bidi_streamer_handle_inputs_first(hostname, expected_inputs, replys, + def run_bidi_streamer_handle_inputs_first(expected_inputs, replys, status) wakey_thread do |mtx, cnd| - c = expect_server_to_be_invoked(hostname, mtx, cnd) + c = expect_server_to_be_invoked(mtx, cnd) expected_inputs.each { |i| expect(c.remote_read).to eq(i) } replys.each { |r| c.remote_send(r) } c.send_status(status, status == @pass ? 'OK' : 'NOK', true) end end - def run_bidi_streamer_echo_ping_pong(hostname, expected_inputs, status, - client_starts) + def run_bidi_streamer_echo_ping_pong(expected_inputs, status, client_starts) wakey_thread do |mtx, cnd| - c = expect_server_to_be_invoked(hostname, mtx, cnd) + c = expect_server_to_be_invoked(mtx, cnd) expected_inputs.each do |i| if client_starts expect(c.remote_read).to eq(i) @@ -450,10 +464,10 @@ describe 'ClientStub' do end end - def run_client_streamer(hostname, expected_inputs, resp, status, **kw) + def run_client_streamer(expected_inputs, resp, status, **kw) wanted_metadata = kw.clone wakey_thread do |mtx, cnd| - c = expect_server_to_be_invoked(hostname, mtx, cnd) + c = expect_server_to_be_invoked(mtx, cnd) expected_inputs.each { |i| expect(c.remote_read).to eq(i) } wanted_metadata.each do |k, v| expect(c.metadata[k.to_s]).to eq(v) @@ -463,10 +477,10 @@ describe 'ClientStub' do end end - def run_request_response(hostname, expected_input, resp, status, **kw) + def run_request_response(expected_input, resp, status, **kw) wanted_metadata = kw.clone wakey_thread do |mtx, cnd| - c = expect_server_to_be_invoked(hostname, mtx, cnd) + c = expect_server_to_be_invoked(mtx, cnd) expect(c.remote_read).to eq(expected_input) wanted_metadata.each do |k, v| expect(c.metadata[k.to_s]).to eq(v) @@ -476,32 +490,30 @@ describe 'ClientStub' do end end - def start_test_server(hostname, awake_mutex, awake_cond) - server_queue = GRPC::Core::CompletionQueue.new - @server = GRPC::Core::Server.new(server_queue, nil) - @server.add_http2_port(hostname) + def create_test_server + @server_queue = GRPC::Core::CompletionQueue.new + @server = GRPC::Core::Server.new(@server_queue, nil) + @server.add_http2_port('0.0.0.0:0') + end + + def start_test_server(awake_mutex, awake_cond) @server.start @server_tag = Object.new @server.request_call(@server_tag) awake_mutex.synchronize { awake_cond.signal } - server_queue end - def expect_server_to_be_invoked(hostname, awake_mutex, awake_cond) - server_queue = start_test_server(hostname, awake_mutex, awake_cond) - ev = server_queue.pluck(@server_tag, INFINITE_FUTURE) + def expect_server_to_be_invoked(awake_mutex, awake_cond) + start_test_server(awake_mutex, awake_cond) + ev = @server_queue.pluck(@server_tag, INFINITE_FUTURE) fail OutOfTime if ev.nil? server_call = ev.call server_call.metadata = ev.result.metadata finished_tag = Object.new - server_call.server_accept(server_queue, finished_tag) + server_call.server_accept(@server_queue, finished_tag) server_call.server_end_initial_metadata - GRPC::ActiveCall.new(server_call, server_queue, NOOP, NOOP, INFINITE_FUTURE, + GRPC::ActiveCall.new(server_call, @server_queue, NOOP, NOOP, + INFINITE_FUTURE, finished_tag: finished_tag) end - - def new_test_host - port = find_unused_tcp_port - "localhost:#{port}" - end end -- cgit v1.2.3 From a8ecbe9a10e02bef17cb9a5aed094a93b56bd906 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 18:27:48 -0800 Subject: Removes port_picker from rpc_server_spec --- src/ruby/spec/generic/rpc_server_spec.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb index cd4888a3b4..e083bc1e9d 100644 --- a/src/ruby/spec/generic/rpc_server_spec.rb +++ b/src/ruby/spec/generic/rpc_server_spec.rb @@ -29,7 +29,6 @@ require 'grpc' require 'xray/thread_dump_signal_handler' -require_relative '../port_picker' def load_test_certs test_root = File.join(File.dirname(File.dirname(__FILE__)), 'testdata') @@ -104,10 +103,10 @@ describe GRPC::RpcServer do @noop = proc { |x| x } @server_queue = GRPC::Core::CompletionQueue.new - port = find_unused_tcp_port - @host = "localhost:#{port}" + server_host = '0.0.0.0:0' @server = GRPC::Core::Server.new(@server_queue, nil) - @server.add_http2_port(@host) + server_port = @server.add_http2_port(server_host) + @host = "localhost:#{server_port}" @ch = GRPC::Core::Channel.new(@host, nil) end -- cgit v1.2.3 From f875aa36982970144df62de996ed48a80b1d4c37 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 18:29:51 -0800 Subject: Removed port_picker from active_call_spec, fixed some style issues --- src/ruby/lib/grpc/generic/active_call.rb | 2 +- src/ruby/spec/generic/active_call_spec.rb | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb index 1cdc168bfe..6c2b6e91c2 100644 --- a/src/ruby/lib/grpc/generic/active_call.rb +++ b/src/ruby/lib/grpc/generic/active_call.rb @@ -67,7 +67,7 @@ module Google fail(ArgumentError, 'not a CompletionQueue') end call.add_metadata(kw) if kw.length > 0 - invoke_accepted, client_metadata_read = Object.new, Object.new + client_metadata_read = Object.new finished_tag = Object.new call.invoke(q, client_metadata_read, finished_tag) [finished_tag, client_metadata_read] diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb index 443ba3d192..e81b2168b0 100644 --- a/src/ruby/spec/generic/active_call_spec.rb +++ b/src/ruby/spec/generic/active_call_spec.rb @@ -28,7 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' -require_relative '../port_picker' include GRPC::Core::StatusCodes @@ -45,12 +44,11 @@ describe GRPC::ActiveCall do @client_queue = GRPC::Core::CompletionQueue.new @server_queue = GRPC::Core::CompletionQueue.new - port = find_unused_tcp_port - host = "localhost:#{port}" + host = '0.0.0.0:0' @server = GRPC::Core::Server.new(@server_queue, nil) - @server.add_http2_port(host) + server_port = @server.add_http2_port(host) @server.start - @ch = GRPC::Core::Channel.new(host, nil) + @ch = GRPC::Core::Channel.new("localhost:#{server_port}", nil) end after(:each) do @@ -206,7 +204,7 @@ describe GRPC::ActiveCall do it 'get a nil msg before a status when an OK status is sent' do call = make_test_call done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue, - deadline) + deadline) client_call = ActiveCall.new(call, @client_queue, @pass_through, @pass_through, deadline, finished_tag: done_tag, -- cgit v1.2.3 From 61ddba35fe7f3f9e859cd3a41c9afa65a4b8132a Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 18:33:20 -0800 Subject: Removed port_picker from server_spec.rb --- src/ruby/spec/server_spec.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/ruby/spec/server_spec.rb b/src/ruby/spec/server_spec.rb index 6e5bb523de..1550ba6566 100644 --- a/src/ruby/spec/server_spec.rb +++ b/src/ruby/spec/server_spec.rb @@ -28,7 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' -require 'port_picker' def load_test_certs test_root = File.join(File.dirname(__FILE__), 'testdata') @@ -205,10 +204,8 @@ describe Server do end def start_a_server - port = find_unused_tcp_port - host = "localhost:#{port}" s = Server.new(@cq, nil) - s.add_http2_port(host) + s.add_http2_port('0.0.0.0:0') s.start s end -- cgit v1.2.3 From d02d1d50b7da63b575d5dea2bb06a9994d141920 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 18:36:17 -0800 Subject: Removes port_picker from call_spec.rb, removes a redundant test --- src/ruby/spec/call_spec.rb | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/src/ruby/spec/call_spec.rb b/src/ruby/spec/call_spec.rb index 9a510df1f3..c793284488 100644 --- a/src/ruby/spec/call_spec.rb +++ b/src/ruby/spec/call_spec.rb @@ -28,7 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' -require 'port_picker' include GRPC::Core::StatusCodes @@ -71,16 +70,8 @@ describe GRPC::Core::Call do before(:each) do @tag = Object.new @client_queue = GRPC::Core::CompletionQueue.new - @server_queue = GRPC::Core::CompletionQueue.new - port = find_unused_tcp_port - host = "localhost:#{port}" - @server = GRPC::Core::Server.new(@server_queue, nil) - @server.add_http2_port(host) - @ch = GRPC::Core::Channel.new(host, nil) - end - - after(:each) do - @server.close + fake_host = 'localhost:10101' + @ch = GRPC::Core::Channel.new(fake_host, nil) end describe '#start_read' do @@ -122,19 +113,6 @@ describe GRPC::Core::Call do end end - describe '#start_write' do - it 'should cause the WRITE_ACCEPTED event' do - call = make_test_call - call.invoke(@client_queue, @tag, @tag) - expect(call.start_write(GRPC::Core::ByteBuffer.new('test_start_write'), - @tag)).to be_nil - ev = @client_queue.next(deadline) - expect(ev.call).to be_a(GRPC::Core::Call) - expect(ev.type).to be(GRPC::Core::CompletionType::WRITE_ACCEPTED) - expect(ev.tag).to be(@tag) - end - end - describe '#status' do it 'can save the status and read it back' do call = make_test_call -- cgit v1.2.3 From 72f14c3e35ba7db91d46ef1b6518b7884469fdbe Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 18:41:00 -0800 Subject: Removes port_picker from channel_spec --- src/ruby/spec/channel_spec.rb | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/ruby/spec/channel_spec.rb b/src/ruby/spec/channel_spec.rb index 820dbd39e9..189d1c67ab 100644 --- a/src/ruby/spec/channel_spec.rb +++ b/src/ruby/spec/channel_spec.rb @@ -28,7 +28,8 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' -require 'port_picker' + +FAKE_HOST='localhost:0' def load_test_certs test_root = File.join(File.dirname(__FILE__), 'testdata') @@ -114,8 +115,7 @@ describe GRPC::Core::Channel do describe '#create_call' do it 'creates a call OK' do - port = find_unused_tcp_port - host = "localhost:#{port}" + host = FAKE_HOST ch = GRPC::Core::Channel.new(host, nil) deadline = Time.now + 5 @@ -127,8 +127,7 @@ describe GRPC::Core::Channel do end it 'raises an error if called on a closed channel' do - port = find_unused_tcp_port - host = "localhost:#{port}" + host = FAKE_HOST ch = GRPC::Core::Channel.new(host, nil) ch.close @@ -142,16 +141,14 @@ describe GRPC::Core::Channel do describe '#destroy' do it 'destroys a channel ok' do - port = find_unused_tcp_port - host = "localhost:#{port}" + host = FAKE_HOST ch = GRPC::Core::Channel.new(host, nil) blk = proc { ch.destroy } expect(&blk).to_not raise_error end it 'can be called more than once without error' do - port = find_unused_tcp_port - host = "localhost:#{port}" + host = FAKE_HOST ch = GRPC::Core::Channel.new(host, nil) blk = proc { ch.destroy } blk.call @@ -167,16 +164,14 @@ describe GRPC::Core::Channel do describe '#close' do it 'closes a channel ok' do - port = find_unused_tcp_port - host = "localhost:#{port}" + host = FAKE_HOST ch = GRPC::Core::Channel.new(host, nil) blk = proc { ch.close } expect(&blk).to_not raise_error end it 'can be called more than once without error' do - port = find_unused_tcp_port - host = "localhost:#{port}" + host = FAKE_HOST ch = GRPC::Core::Channel.new(host, nil) blk = proc { ch.close } blk.call -- cgit v1.2.3 From a816818716f3389549cd360b467a1a176d5f1e00 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 18:41:24 -0800 Subject: Removes remaining references to port_picker --- src/ruby/spec/client_server_spec.rb | 1 - src/ruby/spec/generic/client_stub_spec.rb | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb index 567206ea6f..96b8ef4300 100644 --- a/src/ruby/spec/client_server_spec.rb +++ b/src/ruby/spec/client_server_spec.rb @@ -28,7 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' -require 'port_picker' require 'spec_helper' include GRPC::Core::CompletionType diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb index 1f9c9857b3..f1500fbd44 100644 --- a/src/ruby/spec/generic/client_stub_spec.rb +++ b/src/ruby/spec/generic/client_stub_spec.rb @@ -31,7 +31,7 @@ require 'grpc' require 'xray/thread_dump_signal_handler' NOOP = proc { |x| x } -FAKE_HOST = 'localhost:50505' +FAKE_HOST = 'localhost:0' def wakey_thread(&blk) awake_mutex, awake_cond = Mutex.new, ConditionVariable.new -- cgit v1.2.3 From a398a342ae138f3feabb70fd351116cedf5c49a1 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 18:42:12 -0800 Subject: Remove port_picker.rb --- src/ruby/spec/port_picker.rb | 45 -------------------------------------------- 1 file changed, 45 deletions(-) delete mode 100644 src/ruby/spec/port_picker.rb diff --git a/src/ruby/spec/port_picker.rb b/src/ruby/spec/port_picker.rb deleted file mode 100644 index 98ffbacc1b..0000000000 --- a/src/ruby/spec/port_picker.rb +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2014, 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. - -require 'socket' - -# @param [Fixnum] the minimum port number to accept -# @param [Fixnum] the maximum port number to accept -# @return [Fixnum ]a free tcp port -def find_unused_tcp_port(min = 32_768, max = 60_000) - # Allow the system to assign a port, by specifying 0. - # Loop until a port is assigned in the required range - loop do - socket = Socket.new(:INET, :STREAM, 0) - socket.bind(Addrinfo.tcp('127.0.0.1', 0)) - p = socket.local_address.ip_port - socket.close - return p if p > min && p < max - end -end -- cgit v1.2.3 From 9cae580877947652f6a3edcfd4ec1a043556f4df Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 19:05:16 -0800 Subject: Added the use_tls flag toggle connecting securely --- src/ruby/bin/interop/interop_client.rb | 25 +++++++++++++++++-------- src/ruby/bin/interop/interop_server.rb | 20 +++++++++++++++----- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/ruby/bin/interop/interop_client.rb b/src/ruby/bin/interop/interop_client.rb index 0ea7f376be..a23d8067f5 100755 --- a/src/ruby/bin/interop/interop_client.rb +++ b/src/ruby/bin/interop/interop_client.rb @@ -69,14 +69,19 @@ def test_creds end # creates a test stub that accesses host:port securely. -def create_stub(host, port) +def create_stub(host, port, is_secure) address = "#{host}:#{port}" - stub_opts = { - :creds => test_creds, - GRPC::Core::Channel::SSL_TARGET => 'foo.test.google.com' - } - logger.info("... connecting securely to #{address}") - Grpc::Testing::TestService::Stub.new(address, **stub_opts) + if is_secure + stub_opts = { + :creds => test_creds, + GRPC::Core::Channel::SSL_TARGET => 'foo.test.google.com' + } + logger.info("... connecting securely to #{address}") + Grpc::Testing::TestService::Stub.new(address, **stub_opts) + else + logger.info("... connecting insecurely to #{address}") + Grpc::Testing::TestService::Stub.new(address) + end end # produces a string of null chars (\0) of length l. @@ -216,6 +221,7 @@ end # validates the the command line options, returning them as a Hash. def parse_options options = { + 'secure' => false, 'server_host' => nil, 'server_port' => nil, 'test_case' => nil @@ -235,6 +241,9 @@ def parse_options " (#{test_case_list})") do |v| options['test_case'] = v end + opts.on('-u', '--use_tls', 'access using test creds') do |v| + options['secure'] = v + end end.parse! %w(server_host server_port test_case).each do |arg| @@ -247,7 +256,7 @@ end def main opts = parse_options - stub = create_stub(opts['server_host'], opts['server_port']) + stub = create_stub(opts['server_host'], opts['server_port'], opts['secure']) NamedTests.new(stub).method(opts['test_case']).call end diff --git a/src/ruby/bin/interop/interop_server.rb b/src/ruby/bin/interop/interop_server.rb index 83212823f6..441f609713 100755 --- a/src/ruby/bin/interop/interop_server.rb +++ b/src/ruby/bin/interop/interop_server.rb @@ -154,13 +154,18 @@ end # validates the the command line options, returning them as a Hash. def parse_options options = { - 'port' => nil + 'port' => nil, + 'secure' => false } OptionParser.new do |opts| opts.banner = 'Usage: --port port' opts.on('--port PORT', 'server port') do |v| options['port'] = v end + opts.on('-u', '--use_tls', 'access using test creds') do |v| + options['secure'] = v + end + end.parse! if options['port'].nil? @@ -172,10 +177,15 @@ end def main opts = parse_options host = "0.0.0.0:#{opts['port']}" - s = GRPC::RpcServer.new(creds: test_server_creds) - s.add_http2_port(host, true) - logger.info("... running securely on #{host}") - + if opts['secure'] + s = GRPC::RpcServer.new(creds: test_server_creds) + s.add_http2_port(host, true) + logger.info("... running securely on #{host}") + else + s = GRPC::RpcServer.new + s.add_http2_port(host) + logger.info("... running insecurely on #{host}") + end s.handle(TestTarget) s.run end -- cgit v1.2.3 From 965dda629e53166f8c7edbd634c4110d1cd13bdb Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 19:06:51 -0800 Subject: Removes the test state tracking, that's available on Jenkins --- src/ruby/bin/interop/interop_client.rb | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/ruby/bin/interop/interop_client.rb b/src/ruby/bin/interop/interop_client.rb index a23d8067f5..702db0d22f 100755 --- a/src/ruby/bin/interop/interop_client.rb +++ b/src/ruby/bin/interop/interop_client.rb @@ -138,20 +138,12 @@ class NamedTests @stub = stub end - # TESTING - # PASSED - # FAIL - # ruby server: fails protobuf-ruby can't pass an empty message def empty_unary resp = @stub.empty_call(Empty.new) assert resp.is_a?(Empty), 'empty_unary: invalid response' p 'OK: empty_unary' end - # TESTING - # PASSED - # ruby server - # FAILED def large_unary req_size, wanted_response_size = 271_828, 314_159 payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size)) @@ -168,10 +160,6 @@ class NamedTests p 'OK: large_unary' end - # TESTING: - # PASSED - # ruby server - # FAILED def client_streaming msg_sizes = [27_182, 8, 1828, 45_904] wanted_aggregate_size = 74_922 @@ -185,10 +173,6 @@ class NamedTests p 'OK: client_streaming' end - # TESTING: - # PASSED - # ruby server - # FAILED def server_streaming msg_sizes = [31_415, 9, 2653, 58_979] response_spec = msg_sizes.map { |s| ResponseParameters.new(size: s) } @@ -205,10 +189,6 @@ class NamedTests p 'OK: server_streaming' end - # TESTING: - # PASSED - # ruby server - # FAILED def ping_pong msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]] ppp = PingPongPlayer.new(msg_sizes) -- cgit v1.2.3 From 4eecb5da1ad1431ce5dcef2a8767d25e7b79c8c9 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 19:22:43 -0800 Subject: Adds a flag for running all the tests --- src/ruby/bin/interop/interop_client.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ruby/bin/interop/interop_client.rb b/src/ruby/bin/interop/interop_client.rb index 702db0d22f..4c9c24be15 100755 --- a/src/ruby/bin/interop/interop_client.rb +++ b/src/ruby/bin/interop/interop_client.rb @@ -196,6 +196,15 @@ class NamedTests resps.each { |r| ppp.queue.push(r) } p 'OK: ping_pong' end + + def all + all_methods = NamedTests.instance_methods(false).map(&:to_s) + all_methods.each do |m| + next if m == 'all' or m.start_with?('assert') + p "TESTCASE: #{m}" + self.method(m).call + end + end end # validates the the command line options, returning them as a Hash. -- cgit v1.2.3 From 6e1f10d7579fe97c6b19e8cb5a16668ce3afb0a2 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 19:54:13 -0800 Subject: Adds a dependency on signet. It's to be used for auth, but for now it sslconfig module is required --- src/ruby/grpc.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ruby/grpc.gemspec b/src/ruby/grpc.gemspec index 450362f5a8..ffd084dc91 100755 --- a/src/ruby/grpc.gemspec +++ b/src/ruby/grpc.gemspec @@ -22,6 +22,7 @@ Gem::Specification.new do |s| s.add_dependency 'xray' s.add_dependency 'logging', '~> 1.8' s.add_dependency 'google-protobuf', '~> 3.0.0alpha.1.1' + s.add_dependency 'signet', '~> 0.5.1' s.add_dependency 'minitest', '~> 5.4' # reqd for interop tests s.add_development_dependency 'bundler', '~> 1.7' -- cgit v1.2.3 From 2854ad7aa4db1e7df4a386cac5c3946d6b15de90 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 19:55:12 -0800 Subject: Adds support for overriding the server host name during SSL --- src/ruby/bin/interop/interop_client.rb | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/ruby/bin/interop/interop_client.rb b/src/ruby/bin/interop/interop_client.rb index 4c9c24be15..c5e87a7ba2 100755 --- a/src/ruby/bin/interop/interop_client.rb +++ b/src/ruby/bin/interop/interop_client.rb @@ -69,12 +69,12 @@ def test_creds end # creates a test stub that accesses host:port securely. -def create_stub(host, port, is_secure) +def create_stub(host, port, is_secure, host_override) address = "#{host}:#{port}" if is_secure stub_opts = { :creds => test_creds, - GRPC::Core::Channel::SSL_TARGET => 'foo.test.google.com' + GRPC::Core::Channel::SSL_TARGET => host_override } logger.info("... connecting securely to #{address}") Grpc::Testing::TestService::Stub.new(address, **stub_opts) @@ -212,6 +212,7 @@ def parse_options options = { 'secure' => false, 'server_host' => nil, + 'server_host_override' => nil, 'server_port' => nil, 'test_case' => nil } @@ -220,6 +221,10 @@ def parse_options opts.on('--server_host SERVER_HOST', 'server hostname') do |v| options['server_host'] = v end + opts.on('--server_host_override HOST_OVERRIDE', + 'override host via a HTTP header') do |v| + options['server_host_override'] = v + end opts.on('--server_port SERVER_PORT', 'server port') do |v| options['server_port'] = v end @@ -240,12 +245,16 @@ def parse_options fail(OptionParser::MissingArgument, "please specify --#{arg}") end end + if options['server_host_override'].nil? + options['server_host_override'] = options['server_host'] + end options end def main opts = parse_options - stub = create_stub(opts['server_host'], opts['server_port'], opts['secure']) + stub = create_stub(opts['server_host'], opts['server_port'], opts['secure'], + opts['server_host_override']) NamedTests.new(stub).method(opts['test_case']).call end -- cgit v1.2.3 From 426167c88e2711b9afb58ee48d63dc3ed18712a7 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Mon, 26 Jan 2015 22:22:37 -0800 Subject: Allows production certificates to be specified --- src/ruby/bin/interop/interop_client.rb | 52 +++++++++++++++++++++++++++------- src/ruby/bin/interop/interop_server.rb | 3 +- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/ruby/bin/interop/interop_client.rb b/src/ruby/bin/interop/interop_client.rb index c5e87a7ba2..86739b7b67 100755 --- a/src/ruby/bin/interop/interop_client.rb +++ b/src/ruby/bin/interop/interop_client.rb @@ -54,6 +54,8 @@ require 'test/cpp/interop/test_services' require 'test/cpp/interop/messages' require 'test/cpp/interop/empty' +require 'signet/ssl_config' + # loads the certificates used to access the test server securely. def load_test_certs this_dir = File.expand_path(File.dirname(__FILE__)) @@ -62,18 +64,41 @@ def load_test_certs files.map { |f| File.open(File.join(data_dir, f)).read } end +# loads the certificates used to access the test server securely. +def load_prod_cert + fail 'could not find a production cert' if ENV['SSL_CERT_FILE'].nil? + p "loading prod certs from #{ENV['SSL_CERT_FILE']}" + File.open(ENV['SSL_CERT_FILE']).read +end + # creates a Credentials from the test certificates. def test_creds certs = load_test_certs GRPC::Core::Credentials.new(certs[0]) end +RX_CERT = /-----BEGIN CERTIFICATE-----\n.*?-----END CERTIFICATE-----\n/m + + +# creates a Credentials from the production certificates. +def prod_creds + cert_text = load_prod_cert + GRPC::Core::Credentials.new(cert_text) +end + # creates a test stub that accesses host:port securely. -def create_stub(host, port, is_secure, host_override) +def create_stub(host, port, is_secure, host_override, use_test_ca) address = "#{host}:#{port}" if is_secure + creds = nil + if use_test_ca + creds = test_creds + else + creds = prod_creds + end + stub_opts = { - :creds => test_creds, + :creds => creds, GRPC::Core::Channel::SSL_TARGET => host_override } logger.info("... connecting securely to #{address}") @@ -200,9 +225,9 @@ class NamedTests def all all_methods = NamedTests.instance_methods(false).map(&:to_s) all_methods.each do |m| - next if m == 'all' or m.start_with?('assert') + next if m == 'all' || m.start_with?('assert') p "TESTCASE: #{m}" - self.method(m).call + method(m).call end end end @@ -235,26 +260,33 @@ def parse_options " (#{test_case_list})") do |v| options['test_case'] = v end - opts.on('-u', '--use_tls', 'access using test creds') do |v| + opts.on('-s', '--use_tls', 'require a secure connection?') do |v| options['secure'] = v end + opts.on('-t', '--use_test_ca', + 'if secure, use the test certificate?') do |v| + options['use_test_ca'] = v + end end.parse! + _check_options(options) +end +def _check_options(opts) %w(server_host server_port test_case).each do |arg| - if options[arg].nil? + if opts[arg].nil? fail(OptionParser::MissingArgument, "please specify --#{arg}") end end - if options['server_host_override'].nil? - options['server_host_override'] = options['server_host'] + if opts['server_host_override'].nil? + opts['server_host_override'] = opts['server_host'] end - options + opts end def main opts = parse_options stub = create_stub(opts['server_host'], opts['server_port'], opts['secure'], - opts['server_host_override']) + opts['server_host_override'], opts['use_test_ca']) NamedTests.new(stub).method(opts['test_case']).call end diff --git a/src/ruby/bin/interop/interop_server.rb b/src/ruby/bin/interop/interop_server.rb index 441f609713..cc4d260879 100755 --- a/src/ruby/bin/interop/interop_server.rb +++ b/src/ruby/bin/interop/interop_server.rb @@ -162,10 +162,9 @@ def parse_options opts.on('--port PORT', 'server port') do |v| options['port'] = v end - opts.on('-u', '--use_tls', 'access using test creds') do |v| + opts.on('-s', '--use_tls', 'require a secure connection?') do |v| options['secure'] = v end - end.parse! if options['port'].nil? -- cgit v1.2.3 From 372755606c1d11a8828d55a079792883fd11d5d8 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Tue, 27 Jan 2015 05:03:48 -0800 Subject: Updates the ruby dockerfile to copy the cacerts directory from the docker host --- tools/dockerfile/grpc_ruby/Dockerfile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/dockerfile/grpc_ruby/Dockerfile b/tools/dockerfile/grpc_ruby/Dockerfile index c677ceffff..f01f81d539 100644 --- a/tools/dockerfile/grpc_ruby/Dockerfile +++ b/tools/dockerfile/grpc_ruby/Dockerfile @@ -6,6 +6,9 @@ RUN cd /var/local/git/grpc \ && git pull --recurse-submodules \ && git submodule update --init --recursive +# TODO: remove this, once make install is fixed +RUN touch /var/local/git/grpc/include/grpc/support/string.h + # Build the C core. RUN make install_c -C /var/local/git/grpc @@ -18,5 +21,8 @@ RUN /bin/bash -l -c 'cd /var/local/git/grpc/src/ruby && bundle && rake compile:g # - however, the interop server and client run OK, so this bug can be investigated # RUN /bin/bash -l -c 'cd /var/local/git/grpc/src/ruby && bundle && rake' +# Add a cacerts directory containing the Google root pem file, allowing the ruby client to access the production test instance +ADD cacerts cacerts + # Specify the default command such that the interop server runs on its known testing port -CMD ["/bin/bash", "-l", "-c", "ruby /var/local/git/grpc/src/ruby/bin/interop/interop_server.rb --port 8060"] +CMD ["/bin/bash", "-l", "-c", "ruby /var/local/git/grpc/src/ruby/bin/interop/interop_server.rb --use_tls --port 8060"] -- cgit v1.2.3 From 83182941b523b653e40cf8dfc07d3158ffb2ffd0 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Tue, 27 Jan 2015 05:05:56 -0800 Subject: Updates/Adds test commands - the client test gets new, necessary flags - adds a prod test command that explicitly sets the SSL_CERT_FILE to pick up certs that the c core can load successfully. --- tools/gce_setup/grpc_docker.sh | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tools/gce_setup/grpc_docker.sh b/tools/gce_setup/grpc_docker.sh index 3c2c5ae67a..a73d3fd080 100755 --- a/tools/gce_setup/grpc_docker.sh +++ b/tools/gce_setup/grpc_docker.sh @@ -723,10 +723,27 @@ grpc_cloud_prod_test() { grpc_interop_gen_ruby_cmd() { local cmd_prefix="sudo docker run grpc/ruby bin/bash -l -c" local test_script="/var/local/git/grpc/src/ruby/bin/interop/interop_client.rb" + local the_cmd="$cmd_prefix 'ruby $test_script --use_test_ca --use_tls $@'" + echo $the_cmd +} + + +# constructs the full dockerized java interop test cmd. +# +# call-seq: +# flags= .... # generic flags to include the command +# cmd=$($grpc_gen_test_cmd $flags) +grpc_cloud_prod_gen_ruby_cmd() { + local cmd_prefix="sudo docker run grpc/ruby bin/bash -l -c" + local test_script="/var/local/git/grpc/src/ruby/bin/interop/interop_client.rb" + local test_script+=" --use_tls-true" + local gfe_flags=" --server_port=443 --server_host=grpc-test.sandbox.google.com --server_host_override=grpc-test.sandbox.google.com" + local env_prefix="SSL_CERT_FILE=/cacerts/roots.pem" local the_cmd="$cmd_prefix 'ruby $test_script $@'" echo $the_cmd } + # constructs the full dockerized Go interop test cmd. # # call-seq: @@ -803,7 +820,7 @@ grpc_interop_gen_cxx_cmd() { # flags= .... # generic flags to include the command # cmd=$($grpc_gen_test_cmd $flags) grpc_cloud_prod_gen_cxx_cmd() { - local cmd_prefix="sudo docker run grpc/cxx"; + local cmd_prefix="sudo docker run grpc/cxx"; local test_script="/var/local/git/grpc/bins/opt/interop_client --enable_ssl"; local gfe_flags=" --use_prod_roots --server_port=443 --server_host=grpc-test.sandbox.google.com --server_host_override=grpc-test.sandbox.google.com" local the_cmd="$cmd_prefix $test_script $gfe_flags $@"; -- cgit v1.2.3 From c3aabdd121f4ffe6ed7e88aebfbee7cc714c1627 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Tue, 27 Jan 2015 05:08:06 -0800 Subject: Adds a func for installing the Googles's roots.pem roots.pem is not added to source control, but is instead saved on GCS. The func copies roots.pem to docker host, to a location that can referenced by Dockerfiles using the ADD directive --- tools/gce_setup/shared_startup_funcs.sh | 38 ++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/tools/gce_setup/shared_startup_funcs.sh b/tools/gce_setup/shared_startup_funcs.sh index f1dbca9a2e..69f6ba8cc0 100755 --- a/tools/gce_setup/shared_startup_funcs.sh +++ b/tools/gce_setup/shared_startup_funcs.sh @@ -405,14 +405,18 @@ grpc_dockerfile_install() { # For specific base images, sync the ssh key into the .ssh dir in the dockerfile context [[ $image_label == "grpc/base" ]] && { - grpc_docker_sync_github_key $dockerfile_dir/.ssh 'base_ssh_key'|| return 1; + grpc_docker_sync_github_key $dockerfile_dir/.ssh 'base_ssh_key' || return 1; } [[ $image_label == "grpc/go" ]] && { - grpc_docker_sync_github_key $dockerfile_dir/.ssh 'go_ssh_key'|| return 1; + grpc_docker_sync_github_key $dockerfile_dir/.ssh 'go_ssh_key' || return 1; } [[ $image_label == "grpc/java_base" ]] && { - grpc_docker_sync_github_key $dockerfile_dir/.ssh 'java_base_ssh_key'|| return 1; + grpc_docker_sync_github_key $dockerfile_dir/.ssh 'java_base_ssh_key' || return 1; } + [[ $image_label == "grpc/ruby" ]] && { + grpc_docker_sync_roots_pem $dockerfile_dir/cacerts || return 1; + } + # TODO(temiola): maybe make cache/no-cache a func option? sudo docker build $cache_opt -t $image_label $dockerfile_dir || { @@ -471,3 +475,31 @@ grpc_docker_sync_github_key() { } gsutil cp $src $gcs_key_path $local_key_path } + +# grpc_docker_sync_roots_pem. +# +# Copies the root pems from GCS to the target dir +# +# call-seq: +# grpc_docker_sync_roots_pem +grpc_docker_sync_roots_pem() { + local target_dir=$1 + [[ -n $target_dir ]] || { echo "$FUNCNAME: missing arg: target_dir" >&2; return 1; } + + # determine the admin root; the parent of the dockerfile root, + local gs_dockerfile_root=$(load_metadata "attributes/gs_dockerfile_root") + [[ -n $gs_dockerfile_root ]] || { + echo "$FUNCNAME: missing metadata: gs_dockerfile_root" >&2 + return 1 + } + local gcs_admin_root=$(dirname $gs_dockerfile_root) + + # cp the file from gsutil to a known local area + local gcs_certs_path=$gcs_admin_root/cacerts/roots.pem + local local_certs_path=$target_dir/roots.pem + mkdir -p $target_dir || { + echo "$FUNCNAME: could not create dir: $target_dir" 1>&2 + return 1 + } + gsutil cp $src $gcs_certs_path $local_certs_path +} -- cgit v1.2.3 From 45bc600bdc593fb9dd753fc3d85e52433ba00c0e Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 27 Jan 2015 09:15:38 -0800 Subject: Restrict gcov to c/c++ for now --- tools/run_tests/run_lcov.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/run_tests/run_lcov.sh b/tools/run_tests/run_lcov.sh index 6f22b0e8a4..068213a3d2 100755 --- a/tools/run_tests/run_lcov.sh +++ b/tools/run_tests/run_lcov.sh @@ -7,7 +7,7 @@ out=`realpath ${1:-coverage}` root=`realpath $(dirname $0)/../..` tmp=`mktemp` cd $root -tools/run_tests/run_tests.py -c gcov +tools/run_tests/run_tests.py -c gcov -l c c++ lcov --capture --directory . --output-file $tmp genhtml $tmp --output-directory $out rm $tmp -- cgit v1.2.3 From 78d56535fb1e7dece3fc995baed37ec65032c4f9 Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Tue, 27 Jan 2015 09:29:43 -0800 Subject: Fixes the prod test command flags --- tools/gce_setup/grpc_docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/gce_setup/grpc_docker.sh b/tools/gce_setup/grpc_docker.sh index a73d3fd080..3a37b2f00b 100755 --- a/tools/gce_setup/grpc_docker.sh +++ b/tools/gce_setup/grpc_docker.sh @@ -739,7 +739,7 @@ grpc_cloud_prod_gen_ruby_cmd() { local test_script+=" --use_tls-true" local gfe_flags=" --server_port=443 --server_host=grpc-test.sandbox.google.com --server_host_override=grpc-test.sandbox.google.com" local env_prefix="SSL_CERT_FILE=/cacerts/roots.pem" - local the_cmd="$cmd_prefix 'ruby $test_script $@'" + local the_cmd="$cmd_prefix '$env_prefix ruby $test_script $gfe_flags $@'" echo $the_cmd } -- cgit v1.2.3 From a54b60d427f072423df514bed47bae83ec8d6404 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 27 Jan 2015 09:46:33 -0800 Subject: added src/core/support/string.h to build.json --- build.json | 1 + vsprojects/vs2013/gpr.vcxproj | 1 + vsprojects/vs2013/gpr.vcxproj.filters | 3 +++ 3 files changed, 5 insertions(+) diff --git a/build.json b/build.json index dbc8276eb7..b90b1ca92e 100644 --- a/build.json +++ b/build.json @@ -217,6 +217,7 @@ "headers": [ "src/core/support/cpu.h", "src/core/support/murmur_hash.h", + "src/core/support/string.h", "src/core/support/thd_internal.h" ], "src": [ diff --git a/vsprojects/vs2013/gpr.vcxproj b/vsprojects/vs2013/gpr.vcxproj index 7f05148b88..f71b586aff 100644 --- a/vsprojects/vs2013/gpr.vcxproj +++ b/vsprojects/vs2013/gpr.vcxproj @@ -101,6 +101,7 @@ + diff --git a/vsprojects/vs2013/gpr.vcxproj.filters b/vsprojects/vs2013/gpr.vcxproj.filters index 38b430f651..013ed4b3c9 100644 --- a/vsprojects/vs2013/gpr.vcxproj.filters +++ b/vsprojects/vs2013/gpr.vcxproj.filters @@ -161,6 +161,9 @@ src\core\support + + src\core\support + src\core\support -- cgit v1.2.3 From 103481ec8a7d93e0b120c639aa0c879e5e0aff88 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 27 Jan 2015 10:18:04 -0800 Subject: Add args --- test/core/echo/server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/core/echo/server.c b/test/core/echo/server.c index c20260884b..0d412244c6 100644 --- a/test/core/echo/server.c +++ b/test/core/echo/server.c @@ -143,11 +143,11 @@ int main(int argc, char **argv) { test_server1_cert}; grpc_server_credentials *ssl_creds = grpc_ssl_server_credentials_create(NULL, &pem_key_cert_pair, 1); - server = grpc_secure_server_create(ssl_creds, cq, NULL); + server = grpc_secure_server_create(ssl_creds, cq, &args); GPR_ASSERT(grpc_server_add_secure_http2_port(server, addr)); grpc_server_credentials_release(ssl_creds); } else { - server = grpc_server_create(cq, NULL); + server = grpc_server_create(cq, &args); GPR_ASSERT(grpc_server_add_http2_port(server, addr)); } grpc_server_start(server); -- cgit v1.2.3 From 32960bbbd5517a45ea73dbba47ac6badec70287a Mon Sep 17 00:00:00 2001 From: Tim Emiola Date: Tue, 27 Jan 2015 10:18:16 -0800 Subject: Fixes a bad option spec --- tools/gce_setup/grpc_docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/gce_setup/grpc_docker.sh b/tools/gce_setup/grpc_docker.sh index 3a37b2f00b..16d6ef40e3 100755 --- a/tools/gce_setup/grpc_docker.sh +++ b/tools/gce_setup/grpc_docker.sh @@ -736,7 +736,7 @@ grpc_interop_gen_ruby_cmd() { grpc_cloud_prod_gen_ruby_cmd() { local cmd_prefix="sudo docker run grpc/ruby bin/bash -l -c" local test_script="/var/local/git/grpc/src/ruby/bin/interop/interop_client.rb" - local test_script+=" --use_tls-true" + local test_script+=" --use_tls" local gfe_flags=" --server_port=443 --server_host=grpc-test.sandbox.google.com --server_host_override=grpc-test.sandbox.google.com" local env_prefix="SSL_CERT_FILE=/cacerts/roots.pem" local the_cmd="$cmd_prefix '$env_prefix ruby $test_script $gfe_flags $@'" -- cgit v1.2.3 From ec4e0cb40b944dee55eadfd8324edac7db06837d Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 27 Jan 2015 10:21:57 -0800 Subject: Fix compile --- src/core/channel/call_op_string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/channel/call_op_string.c b/src/core/channel/call_op_string.c index 40d53693c2..127ea707bf 100644 --- a/src/core/channel/call_op_string.c +++ b/src/core/channel/call_op_string.c @@ -84,7 +84,7 @@ char *grpc_call_op_string(grpc_call_op *op) { gpr_strvec_add(&b, gpr_strdup("SEND_MESSAGE")); break; case GRPC_SEND_PREFORMATTED_MESSAGE: - bprintf(&b, "SEND_PREFORMATTED_MESSAGE"); + gpr_strvec_add(&b, gpr_strdup("SEND_PREFORMATTED_MESSAGE")); break; case GRPC_SEND_FINISH: gpr_strvec_add(&b, gpr_strdup("SEND_FINISH")); -- cgit v1.2.3 From d631cf39239d2ee17e464445c3dd0001ac44601f Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 27 Jan 2015 10:35:01 -0800 Subject: Allow access to call stack from call. This API parallels the equivalent one in channel. --- src/core/surface/call.c | 5 +++++ src/core/surface/call.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 14d990df6a..bbd705b0c9 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -981,3 +981,8 @@ void grpc_call_set_deadline(grpc_call_element *elem, gpr_timespec deadline) { call->have_alarm = 1; grpc_alarm_init(&call->alarm, deadline, call_alarm, call, gpr_now()); } + +grpc_call_stack *grpc_call_get_call_stack(grpc_call *call) { + return CALL_STACK_FROM_CALL(call); +} + diff --git a/src/core/surface/call.h b/src/core/surface/call.h index 01605bb38a..804b387cb1 100644 --- a/src/core/surface/call.h +++ b/src/core/surface/call.h @@ -64,6 +64,8 @@ void grpc_call_client_initial_metadata_complete( void grpc_call_set_deadline(grpc_call_element *surface_element, gpr_timespec deadline); +grpc_call_stack *grpc_call_get_call_stack(grpc_call *call); + /* Given the top call_element, get the call object. */ grpc_call *grpc_call_from_top_element(grpc_call_element *surface_element); -- cgit v1.2.3