diff options
author | 2015-08-21 12:02:15 -0700 | |
---|---|---|
committer | 2015-08-21 12:02:15 -0700 | |
commit | 1e9dd32803afed8db333a02aeca000c9ededf2cb (patch) | |
tree | 715e14106d91f41c7022c8aa7a8fbcb997fbdec9 /src | |
parent | e13bfc0139b4ddb560ee3a0e085dbf518a5dabe5 (diff) | |
parent | 3c807eac69acd711620aaf7ab44fd79ce406b35e (diff) |
Merge branch 'master' into node_method_name_conflicts
Diffstat (limited to 'src')
274 files changed, 5068 insertions, 1749 deletions
diff --git a/src/core/channel/census_filter.h b/src/core/channel/census_filter.h index 4f9759f0db..1453c05d28 100644 --- a/src/core/channel/census_filter.h +++ b/src/core/channel/census_filter.h @@ -41,4 +41,4 @@ extern const grpc_channel_filter grpc_client_census_filter; extern const grpc_channel_filter grpc_server_census_filter; -#endif /* GRPC_INTERNAL_CORE_CHANNEL_CENSUS_FILTER_H */ +#endif /* GRPC_INTERNAL_CORE_CHANNEL_CENSUS_FILTER_H */ diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c index 6c2e6b38a8..2e25033813 100644 --- a/src/core/channel/client_channel.c +++ b/src/core/channel/client_channel.c @@ -84,8 +84,10 @@ typedef struct { grpc_pollset_set pollset_set; } channel_data; -/** We create one watcher for each new lb_policy that is returned from a resolver, - to watch for state changes from the lb_policy. When a state change is seen, we +/** We create one watcher for each new lb_policy that is returned from a + resolver, + to watch for state changes from the lb_policy. When a state change is seen, + we update the channel, and create a new watcher */ typedef struct { channel_data *chand; @@ -380,7 +382,8 @@ static void perform_transport_stream_op(grpc_call_element *elem, if (lb_policy) { grpc_transport_stream_op *op = &calld->waiting_op; grpc_pollset *bind_pollset = op->bind_pollset; - grpc_metadata_batch *initial_metadata = &op->send_ops->ops[0].data.metadata; + grpc_metadata_batch *initial_metadata = + &op->send_ops->ops[0].data.metadata; GRPC_LB_POLICY_REF(lb_policy, "pick"); gpr_mu_unlock(&chand->mu_config); calld->state = CALL_WAITING_FOR_PICK; @@ -388,13 +391,14 @@ static void perform_transport_stream_op(grpc_call_element *elem, GPR_ASSERT(op->bind_pollset); GPR_ASSERT(op->send_ops); GPR_ASSERT(op->send_ops->nops >= 1); - GPR_ASSERT( - op->send_ops->ops[0].type == GRPC_OP_METADATA); + GPR_ASSERT(op->send_ops->ops[0].type == GRPC_OP_METADATA); gpr_mu_unlock(&calld->mu_state); - grpc_iomgr_closure_init(&calld->async_setup_task, picked_target, calld); + grpc_iomgr_closure_init(&calld->async_setup_task, picked_target, + calld); grpc_lb_policy_pick(lb_policy, bind_pollset, initial_metadata, - &calld->picked_channel, &calld->async_setup_task); + &calld->picked_channel, + &calld->async_setup_task); GRPC_LB_POLICY_UNREF(lb_policy, "pick"); } else if (chand->resolver != NULL) { @@ -430,7 +434,8 @@ static void cc_start_transport_stream_op(grpc_call_element *elem, perform_transport_stream_op(elem, op, 0); } -static void watch_lb_policy(channel_data *chand, grpc_lb_policy *lb_policy, grpc_connectivity_state current_state); +static void watch_lb_policy(channel_data *chand, grpc_lb_policy *lb_policy, + grpc_connectivity_state current_state); static void on_lb_policy_state_changed(void *arg, int iomgr_success) { lb_policy_connectivity_watcher *w = arg; @@ -450,7 +455,8 @@ static void on_lb_policy_state_changed(void *arg, int iomgr_success) { gpr_free(w); } -static void watch_lb_policy(channel_data *chand, grpc_lb_policy *lb_policy, grpc_connectivity_state current_state) { +static void watch_lb_policy(channel_data *chand, grpc_lb_policy *lb_policy, + grpc_connectivity_state current_state) { lb_policy_connectivity_watcher *w = gpr_malloc(sizeof(*w)); GRPC_CHANNEL_INTERNAL_REF(chand->master, "watch_lb_policy"); @@ -499,13 +505,13 @@ static void cc_on_config_changed(void *arg, int iomgr_success) { if (iomgr_success && chand->resolver) { grpc_resolver *resolver = chand->resolver; GRPC_RESOLVER_REF(resolver, "channel-next"); + grpc_connectivity_state_set(&chand->state_tracker, state, + "new_lb+resolver"); gpr_mu_unlock(&chand->mu_config); GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver"); grpc_resolver_next(resolver, &chand->incoming_configuration, &chand->on_config_changed); GRPC_RESOLVER_UNREF(resolver, "channel-next"); - grpc_connectivity_state_set(&chand->state_tracker, state, - "new_lb+resolver"); if (lb_policy != NULL) { watch_lb_policy(chand, lb_policy, state); } @@ -663,7 +669,8 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, grpc_iomgr_closure_init(&chand->on_config_changed, cc_on_config_changed, chand); - grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, "client_channel"); + grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, + "client_channel"); } /* Destructor for channel_data */ @@ -747,19 +754,20 @@ void grpc_client_channel_watch_connectivity_state( gpr_mu_unlock(&chand->mu_config); } -grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set(grpc_channel_element *elem) { +grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set( + grpc_channel_element *elem) { channel_data *chand = elem->channel_data; return &chand->pollset_set; } void grpc_client_channel_add_interested_party(grpc_channel_element *elem, - grpc_pollset *pollset) { + grpc_pollset *pollset) { channel_data *chand = elem->channel_data; grpc_pollset_set_add_pollset(&chand->pollset_set, pollset); } void grpc_client_channel_del_interested_party(grpc_channel_element *elem, - grpc_pollset *pollset) { + grpc_pollset *pollset) { channel_data *chand = elem->channel_data; grpc_pollset_set_del_pollset(&chand->pollset_set, pollset); } diff --git a/src/core/channel/client_channel.h b/src/core/channel/client_channel.h index cd81294eb3..13681e3956 100644 --- a/src/core/channel/client_channel.h +++ b/src/core/channel/client_channel.h @@ -59,11 +59,12 @@ void grpc_client_channel_watch_connectivity_state( grpc_channel_element *elem, grpc_connectivity_state *state, grpc_iomgr_closure *on_complete); -grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set(grpc_channel_element *elem); +grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set( + grpc_channel_element *elem); void grpc_client_channel_add_interested_party(grpc_channel_element *channel, - grpc_pollset *pollset); + grpc_pollset *pollset); void grpc_client_channel_del_interested_party(grpc_channel_element *channel, - grpc_pollset *pollset); + grpc_pollset *pollset); #endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_CHANNEL_H */ diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c index 8963c13b0f..762a4edc73 100644 --- a/src/core/channel/compress_filter.c +++ b/src/core/channel/compress_filter.c @@ -35,22 +35,25 @@ #include <string.h> #include <grpc/compression.h> +#include <grpc/support/alloc.h> #include <grpc/support/log.h> #include <grpc/support/slice_buffer.h> #include "src/core/channel/compress_filter.h" #include "src/core/channel/channel_args.h" #include "src/core/compression/message_compress.h" +#include "src/core/support/string.h" typedef struct call_data { gpr_slice_buffer slices; /**< Buffers up input slices to be compressed */ grpc_linked_mdelem compression_algorithm_storage; + grpc_linked_mdelem accept_encoding_storage; int remaining_slice_bytes; /**< Input data to be read, as per BEGIN_MESSAGE */ int written_initial_metadata; /**< Already processed initial md? */ /** Compression algorithm we'll try to use. It may be given by incoming * metadata, or by the channel's default compression settings. */ grpc_compression_algorithm compression_algorithm; - /** If true, contents of \a compression_algorithm are authoritative */ + /** If true, contents of \a compression_algorithm are authoritative */ int has_compression_algorithm; } call_data; @@ -59,8 +62,12 @@ typedef struct channel_data { grpc_mdstr *mdstr_request_compression_algorithm_key; /** Metadata key for the outgoing (used) compression algorithm */ grpc_mdstr *mdstr_outgoing_compression_algorithm_key; + /** Metadata key for the accepted encodings */ + grpc_mdstr *mdstr_compression_capabilities_key; /** Precomputed metadata elements for all available compression algorithms */ grpc_mdelem *mdelem_compression_algorithms[GRPC_COMPRESS_ALGORITHMS_COUNT]; + /** Precomputed metadata elements for the accepted encodings */ + grpc_mdelem *mdelem_accept_encoding; /** The default, channel-level, compression algorithm */ grpc_compression_algorithm default_compression_algorithm; } channel_data; @@ -71,7 +78,7 @@ typedef struct channel_data { * * Returns 1 if the data was actually compress and 0 otherwise. */ static int compress_send_sb(grpc_compression_algorithm algorithm, - gpr_slice_buffer *slices) { + gpr_slice_buffer *slices) { int did_compress; gpr_slice_buffer tmp; gpr_slice_buffer_init(&tmp); @@ -86,14 +93,14 @@ static int compress_send_sb(grpc_compression_algorithm algorithm, /** For each \a md element from the incoming metadata, filter out the entry for * "grpc-encoding", using its value to populate the call data's * compression_algorithm field. */ -static grpc_mdelem* compression_md_filter(void *user_data, grpc_mdelem *md) { +static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; if (md->key == channeld->mdstr_request_compression_algorithm_key) { const char *md_c_str = grpc_mdstr_as_c_string(md->value); - if (!grpc_compression_algorithm_parse(md_c_str, + if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str), &calld->compression_algorithm)) { gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'. Ignoring.", md_c_str); @@ -108,10 +115,10 @@ static grpc_mdelem* compression_md_filter(void *user_data, grpc_mdelem *md) { static int skip_compression(channel_data *channeld, call_data *calld) { if (calld->has_compression_algorithm) { - if (calld->compression_algorithm == GRPC_COMPRESS_NONE) { - return 1; - } - return 0; /* we have an actual call-specific algorithm */ + if (calld->compression_algorithm == GRPC_COMPRESS_NONE) { + return 1; + } + return 0; /* we have an actual call-specific algorithm */ } /* no per-call compression override */ return channeld->default_compression_algorithm == GRPC_COMPRESS_NONE; @@ -184,7 +191,7 @@ static void process_send_ops(grpc_call_element *elem, * given by GRPC_OP_BEGIN_MESSAGE) */ calld->remaining_slice_bytes = sop->data.begin_message.length; if (sop->data.begin_message.flags & GRPC_WRITE_NO_COMPRESS) { - calld->has_compression_algorithm = 1; /* GPR_TRUE */ + calld->has_compression_algorithm = 1; /* GPR_TRUE */ calld->compression_algorithm = GRPC_COMPRESS_NONE; } break; @@ -202,10 +209,17 @@ static void process_send_ops(grpc_call_element *elem, channeld->default_compression_algorithm; calld->has_compression_algorithm = 1; /* GPR_TRUE */ } + /* hint compression algorithm */ grpc_metadata_batch_add_tail( &(sop->data.metadata), &calld->compression_algorithm_storage, GRPC_MDELEM_REF(channeld->mdelem_compression_algorithms [calld->compression_algorithm])); + + /* convey supported compression algorithms */ + grpc_metadata_batch_add_tail( + &(sop->data.metadata), &calld->accept_encoding_storage, + GRPC_MDELEM_REF(channeld->mdelem_accept_encoding)); + calld->written_initial_metadata = 1; /* GPR_TRUE */ } break; @@ -279,6 +293,9 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, int is_first, int is_last) { channel_data *channeld = elem->channel_data; grpc_compression_algorithm algo_idx; + const char *supported_algorithms_names[GRPC_COMPRESS_ALGORITHMS_COUNT - 1]; + char *accept_encoding_str; + size_t accept_encoding_str_len; channeld->default_compression_algorithm = grpc_channel_args_get_compression_algorithm(args); @@ -289,6 +306,9 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, channeld->mdstr_outgoing_compression_algorithm_key = grpc_mdstr_from_string(mdctx, "grpc-encoding", 0); + channeld->mdstr_compression_capabilities_key = + grpc_mdstr_from_string(mdctx, "grpc-accept-encoding", 0); + for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) { char *algorithm_name; GPR_ASSERT(grpc_compression_algorithm_name(algo_idx, &algorithm_name) != 0); @@ -297,8 +317,22 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, mdctx, GRPC_MDSTR_REF(channeld->mdstr_outgoing_compression_algorithm_key), grpc_mdstr_from_string(mdctx, algorithm_name, 0)); + if (algo_idx > 0) { + supported_algorithms_names[algo_idx - 1] = algorithm_name; + } } + /* TODO(dgq): gpr_strjoin_sep could be made to work with statically allocated + * arrays, as to avoid the heap allocs */ + accept_encoding_str = gpr_strjoin_sep( + supported_algorithms_names, GPR_ARRAY_SIZE(supported_algorithms_names), + ", ", &accept_encoding_str_len); + + channeld->mdelem_accept_encoding = grpc_mdelem_from_metadata_strings( + mdctx, GRPC_MDSTR_REF(channeld->mdstr_compression_capabilities_key), + grpc_mdstr_from_string(mdctx, accept_encoding_str, 0)); + gpr_free(accept_encoding_str); + GPR_ASSERT(!is_last); } @@ -309,10 +343,11 @@ static void destroy_channel_elem(grpc_channel_element *elem) { GRPC_MDSTR_UNREF(channeld->mdstr_request_compression_algorithm_key); GRPC_MDSTR_UNREF(channeld->mdstr_outgoing_compression_algorithm_key); - for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; - ++algo_idx) { + GRPC_MDSTR_UNREF(channeld->mdstr_compression_capabilities_key); + for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) { GRPC_MDELEM_UNREF(channeld->mdelem_compression_algorithms[algo_idx]); } + GRPC_MDELEM_UNREF(channeld->mdelem_accept_encoding); } const grpc_channel_filter grpc_compress_filter = { diff --git a/src/core/channel/compress_filter.h b/src/core/channel/compress_filter.h index 0694e2c1dd..0917e81ca4 100644 --- a/src/core/channel/compress_filter.h +++ b/src/core/channel/compress_filter.h @@ -62,4 +62,4 @@ extern const grpc_channel_filter grpc_compress_filter; -#endif /* GRPC_INTERNAL_CORE_CHANNEL_COMPRESS_FILTER_H */ +#endif /* GRPC_INTERNAL_CORE_CHANNEL_COMPRESS_FILTER_H */ diff --git a/src/core/channel/http_client_filter.h b/src/core/channel/http_client_filter.h index 04eb839e00..21c66b9b8e 100644 --- a/src/core/channel/http_client_filter.h +++ b/src/core/channel/http_client_filter.h @@ -41,4 +41,4 @@ extern const grpc_channel_filter grpc_http_client_filter; #define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme" -#endif /* GRPC_INTERNAL_CORE_CHANNEL_HTTP_CLIENT_FILTER_H */ +#endif /* GRPC_INTERNAL_CORE_CHANNEL_HTTP_CLIENT_FILTER_H */ diff --git a/src/core/channel/http_server_filter.h b/src/core/channel/http_server_filter.h index 42f76ed17f..f219d4e66f 100644 --- a/src/core/channel/http_server_filter.h +++ b/src/core/channel/http_server_filter.h @@ -39,4 +39,4 @@ /* Processes metadata on the client side for HTTP2 transports */ extern const grpc_channel_filter grpc_http_server_filter; -#endif /* GRPC_INTERNAL_CORE_CHANNEL_HTTP_SERVER_FILTER_H */ +#endif /* GRPC_INTERNAL_CORE_CHANNEL_HTTP_SERVER_FILTER_H */ diff --git a/src/core/channel/noop_filter.h b/src/core/channel/noop_filter.h index 96463e5322..ded9b33117 100644 --- a/src/core/channel/noop_filter.h +++ b/src/core/channel/noop_filter.h @@ -41,4 +41,4 @@ customize for their own filters */ extern const grpc_channel_filter grpc_no_op_filter; -#endif /* GRPC_INTERNAL_CORE_CHANNEL_NOOP_FILTER_H */ +#endif /* GRPC_INTERNAL_CORE_CHANNEL_NOOP_FILTER_H */ diff --git a/src/core/client_config/resolvers/dns_resolver.c b/src/core/client_config/resolvers/dns_resolver.c index 827b1a2be5..7b35b7902f 100644 --- a/src/core/client_config/resolvers/dns_resolver.c +++ b/src/core/client_config/resolvers/dns_resolver.c @@ -219,7 +219,8 @@ static grpc_resolver *dns_create( default_host_arg.type = GRPC_ARG_STRING; default_host_arg.key = GRPC_ARG_DEFAULT_AUTHORITY; default_host_arg.value.string = host; - subchannel_factory = grpc_subchannel_factory_add_channel_arg(subchannel_factory, &default_host_arg); + subchannel_factory = grpc_subchannel_factory_add_channel_arg( + subchannel_factory, &default_host_arg); gpr_free(host); gpr_free(port); diff --git a/src/core/client_config/resolvers/zookeeper_resolver.c b/src/core/client_config/resolvers/zookeeper_resolver.c index a8397a3da1..acb2ba136e 100644 --- a/src/core/client_config/resolvers/zookeeper_resolver.c +++ b/src/core/client_config/resolvers/zookeeper_resolver.c @@ -142,7 +142,7 @@ static void zookeeper_next(grpc_resolver *resolver, gpr_mu_unlock(&r->mu); } -/** Zookeeper global watcher for connection management +/** Zookeeper global watcher for connection management TODO: better connection management besides logs */ static void zookeeper_global_watcher(zhandle_t *zookeeper_handle, int type, int state, const char *path, @@ -172,7 +172,7 @@ static void zookeeper_watcher(zhandle_t *zookeeper_handle, int type, int state, } } -/** Callback function after getting all resolved addresses +/** Callback function after getting all resolved addresses Creates a subchannel for each address */ static void zookeeper_on_resolved(void *arg, grpc_resolved_addresses *addresses) { @@ -249,7 +249,7 @@ static char *zookeeper_parse_address(const char *value, int value_len) { grpc_json *cur; const char *host; const char *port; - char* buffer; + char *buffer; char *address = NULL; buffer = gpr_malloc(value_len); @@ -449,7 +449,7 @@ static grpc_resolver *zookeeper_create( gpr_mu_init(&r->mu); grpc_resolver_init(&r->base, &zookeeper_resolver_vtable); r->name = gpr_strdup(path); - + r->subchannel_factory = subchannel_factory; r->lb_policy_factory = lb_policy_factory; grpc_subchannel_factory_ref(subchannel_factory); diff --git a/src/core/client_config/subchannel.h b/src/core/client_config/subchannel.h index d1cd33b2af..2e36c69134 100644 --- a/src/core/client_config/subchannel.h +++ b/src/core/client_config/subchannel.h @@ -91,8 +91,10 @@ void grpc_subchannel_notify_on_state_change(grpc_subchannel *channel, grpc_connectivity_state *state, grpc_iomgr_closure *notify); +/** express interest in \a channel's activities through \a pollset. */ void grpc_subchannel_add_interested_party(grpc_subchannel *channel, grpc_pollset *pollset); +/** stop following \a channel's activity through \a pollset. */ void grpc_subchannel_del_interested_party(grpc_subchannel *channel, grpc_pollset *pollset); diff --git a/src/core/client_config/subchannel_factory_decorators/add_channel_arg.c b/src/core/client_config/subchannel_factory_decorators/add_channel_arg.c index 7dc6d99ebe..585e465fa4 100644 --- a/src/core/client_config/subchannel_factory_decorators/add_channel_arg.c +++ b/src/core/client_config/subchannel_factory_decorators/add_channel_arg.c @@ -35,9 +35,9 @@ #include "src/core/client_config/subchannel_factory_decorators/merge_channel_args.h" grpc_subchannel_factory *grpc_subchannel_factory_add_channel_arg( - grpc_subchannel_factory *input, const grpc_arg *arg) { - grpc_channel_args args; - args.num_args = 1; - args.args = (grpc_arg *)arg; - return grpc_subchannel_factory_merge_channel_args(input, &args); + grpc_subchannel_factory *input, const grpc_arg *arg) { + grpc_channel_args args; + args.num_args = 1; + args.args = (grpc_arg *)arg; + return grpc_subchannel_factory_merge_channel_args(input, &args); } diff --git a/src/core/client_config/subchannel_factory_decorators/add_channel_arg.h b/src/core/client_config/subchannel_factory_decorators/add_channel_arg.h index 1937623374..8457294000 100644 --- a/src/core/client_config/subchannel_factory_decorators/add_channel_arg.h +++ b/src/core/client_config/subchannel_factory_decorators/add_channel_arg.h @@ -40,6 +40,7 @@ channel_args by adding a new argument; ownership of input, arg is retained by the caller. */ grpc_subchannel_factory *grpc_subchannel_factory_add_channel_arg( - grpc_subchannel_factory *input, const grpc_arg *arg); + grpc_subchannel_factory *input, const grpc_arg *arg); -#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_ADD_CHANNEL_ARG_H */ +#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_ADD_CHANNEL_ARG_H \ + */ diff --git a/src/core/client_config/subchannel_factory_decorators/merge_channel_args.c b/src/core/client_config/subchannel_factory_decorators/merge_channel_args.c index 7e028857ac..c1b5507fde 100644 --- a/src/core/client_config/subchannel_factory_decorators/merge_channel_args.c +++ b/src/core/client_config/subchannel_factory_decorators/merge_channel_args.c @@ -50,7 +50,7 @@ static void merge_args_factory_ref(grpc_subchannel_factory *scf) { static void merge_args_factory_unref(grpc_subchannel_factory *scf) { merge_args_factory *f = (merge_args_factory *)scf; if (gpr_unref(&f->refs)) { - grpc_subchannel_factory_unref(f->wrapped); + grpc_subchannel_factory_unref(f->wrapped); grpc_channel_args_destroy(f->merge_args); gpr_free(f); } @@ -73,7 +73,7 @@ static const grpc_subchannel_factory_vtable merge_args_factory_vtable = { merge_args_factory_create_subchannel}; grpc_subchannel_factory *grpc_subchannel_factory_merge_channel_args( - grpc_subchannel_factory *input, const grpc_channel_args *args) { + grpc_subchannel_factory *input, const grpc_channel_args *args) { merge_args_factory *f = gpr_malloc(sizeof(*f)); f->base.vtable = &merge_args_factory_vtable; gpr_ref_init(&f->refs, 1); diff --git a/src/core/client_config/subchannel_factory_decorators/merge_channel_args.h b/src/core/client_config/subchannel_factory_decorators/merge_channel_args.h index 73a03b752f..f4757f0650 100644 --- a/src/core/client_config/subchannel_factory_decorators/merge_channel_args.h +++ b/src/core/client_config/subchannel_factory_decorators/merge_channel_args.h @@ -40,6 +40,7 @@ channel_args by adding a new argument; ownership of input, args is retained by the caller. */ grpc_subchannel_factory *grpc_subchannel_factory_merge_channel_args( - grpc_subchannel_factory *input, const grpc_channel_args *args); + grpc_subchannel_factory *input, const grpc_channel_args *args); -#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_MERGE_CHANNEL_ARGS_H */ +#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_MERGE_CHANNEL_ARGS_H \ + */ diff --git a/src/core/compression/algorithm.c b/src/core/compression/algorithm.c index 0fd028741e..6ed6dbe93f 100644 --- a/src/core/compression/algorithm.c +++ b/src/core/compression/algorithm.c @@ -35,13 +35,20 @@ #include <string.h> #include <grpc/compression.h> -int grpc_compression_algorithm_parse(const char* name, +int grpc_compression_algorithm_parse(const char *name, size_t name_length, grpc_compression_algorithm *algorithm) { - if (strcmp(name, "identity") == 0) { + /* we use strncmp not only because it's safer (even though in this case it + * doesn't matter, given that we are comparing against string literals, but + * because this way we needn't have "name" nil-terminated (useful for slice + * data, for example) */ + if (name_length == 0) { + return 0; + } + if (strncmp(name, "identity", name_length) == 0) { *algorithm = GRPC_COMPRESS_NONE; - } else if (strcmp(name, "gzip") == 0) { + } else if (strncmp(name, "gzip", name_length) == 0) { *algorithm = GRPC_COMPRESS_GZIP; - } else if (strcmp(name, "deflate") == 0) { + } else if (strncmp(name, "deflate", name_length) == 0) { *algorithm = GRPC_COMPRESS_DEFLATE; } else { return 0; diff --git a/src/core/debug/trace.c b/src/core/debug/trace.c index b53dfe804b..1014b1f4db 100644 --- a/src/core/debug/trace.c +++ b/src/core/debug/trace.c @@ -61,8 +61,8 @@ static void add(const char *beg, const char *end, char ***ss, size_t *ns) { size_t np = n + 1; char *s = gpr_malloc(end - beg + 1); memcpy(s, beg, end - beg); - s[end-beg] = 0; - *ss = gpr_realloc(*ss, sizeof(char**) * np); + s[end - beg] = 0; + *ss = gpr_realloc(*ss, sizeof(char **) * np); (*ss)[n] = s; *ns = np; } @@ -73,7 +73,7 @@ static void split(const char *s, char ***ss, size_t *ns) { add(s, s + strlen(s), ss, ns); } else { add(s, c, ss, ns); - split(c+1, ss, ns); + split(c + 1, ss, ns); } } @@ -125,7 +125,7 @@ int grpc_tracer_set_enabled(const char *name, int enabled) { } if (!found) { gpr_log(GPR_ERROR, "Unknown trace var: '%s'", name); - return 0; /* early return */ + return 0; /* early return */ } } return 1; diff --git a/src/core/debug/trace.h b/src/core/debug/trace.h index fc8615bc69..dc5875976e 100644 --- a/src/core/debug/trace.h +++ b/src/core/debug/trace.h @@ -40,4 +40,4 @@ void grpc_register_tracer(const char *name, int *flag); void grpc_tracer_init(const char *env_var_name); void grpc_tracer_shutdown(void); -#endif /* GRPC_INTERNAL_CORE_DEBUG_TRACE_H */ +#endif /* GRPC_INTERNAL_CORE_DEBUG_TRACE_H */ diff --git a/src/core/httpcli/format_request.c b/src/core/httpcli/format_request.c index e875423e87..6189fce86b 100644 --- a/src/core/httpcli/format_request.c +++ b/src/core/httpcli/format_request.c @@ -43,7 +43,8 @@ #include <grpc/support/string_util.h> #include <grpc/support/useful.h> -static void fill_common_header(const grpc_httpcli_request *request, gpr_strvec *buf) { +static void fill_common_header(const grpc_httpcli_request *request, + gpr_strvec *buf) { size_t i; gpr_strvec_add(buf, gpr_strdup(request->path)); gpr_strvec_add(buf, gpr_strdup(" HTTP/1.0\r\n")); @@ -52,7 +53,8 @@ static void fill_common_header(const grpc_httpcli_request *request, gpr_strvec * 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")); + 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++) { gpr_strvec_add(buf, gpr_strdup(request->hdrs[i].key)); diff --git a/src/core/httpcli/format_request.h b/src/core/httpcli/format_request.h index 8bfb20bfd0..c8dc8f7d4e 100644 --- a/src/core/httpcli/format_request.h +++ b/src/core/httpcli/format_request.h @@ -42,4 +42,4 @@ gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request, const char *body_bytes, size_t body_size); -#endif /* GRPC_INTERNAL_CORE_HTTPCLI_FORMAT_REQUEST_H */ +#endif /* GRPC_INTERNAL_CORE_HTTPCLI_FORMAT_REQUEST_H */ diff --git a/src/core/httpcli/parser.h b/src/core/httpcli/parser.h index 71280e7479..3fbb4c7479 100644 --- a/src/core/httpcli/parser.h +++ b/src/core/httpcli/parser.h @@ -61,4 +61,4 @@ void grpc_httpcli_parser_destroy(grpc_httpcli_parser *parser); int grpc_httpcli_parser_parse(grpc_httpcli_parser *parser, gpr_slice slice); int grpc_httpcli_parser_eof(grpc_httpcli_parser *parser); -#endif /* GRPC_INTERNAL_CORE_HTTPCLI_PARSER_H */ +#endif /* GRPC_INTERNAL_CORE_HTTPCLI_PARSER_H */ diff --git a/src/core/iomgr/alarm.c b/src/core/iomgr/alarm.c index 68d33b9cf6..ddb30dc4bb 100644 --- a/src/core/iomgr/alarm.c +++ b/src/core/iomgr/alarm.c @@ -105,8 +105,7 @@ void grpc_alarm_list_init(gpr_timespec now) { void grpc_alarm_list_shutdown(void) { int i; - while (run_some_expired_alarms(NULL, gpr_inf_future(g_clock_type), NULL, - 0)) + while (run_some_expired_alarms(NULL, gpr_inf_future(g_clock_type), NULL, 0)) ; for (i = 0; i < NUM_SHARDS; i++) { shard_type *shard = &g_shards[i]; @@ -362,7 +361,7 @@ static int run_some_expired_alarms(gpr_mu *drop_mu, gpr_timespec now, int grpc_alarm_check(gpr_mu *drop_mu, gpr_timespec now, gpr_timespec *next) { GPR_ASSERT(now.clock_type == g_clock_type); return run_some_expired_alarms( - drop_mu, now, next, + drop_mu, now, next, gpr_time_cmp(now, gpr_inf_future(now.clock_type)) != 0); } diff --git a/src/core/iomgr/alarm.h b/src/core/iomgr/alarm.h index c067a0b8a3..4a13527e64 100644 --- a/src/core/iomgr/alarm.h +++ b/src/core/iomgr/alarm.h @@ -86,4 +86,4 @@ void grpc_alarm_init(grpc_alarm *alarm, gpr_timespec deadline, Requires: cancel() must happen after add() on a given alarm */ void grpc_alarm_cancel(grpc_alarm *alarm); -#endif /* GRPC_INTERNAL_CORE_IOMGR_ALARM_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_ALARM_H */ diff --git a/src/core/iomgr/alarm_heap.c b/src/core/iomgr/alarm_heap.c index d912178fda..daed251982 100644 --- a/src/core/iomgr/alarm_heap.c +++ b/src/core/iomgr/alarm_heap.c @@ -66,11 +66,11 @@ static void adjust_downwards(grpc_alarm **first, int i, int length, int next_i; if (left_child >= length) break; right_child = left_child + 1; - next_i = - right_child < length && gpr_time_cmp(first[left_child]->deadline, - first[right_child]->deadline) < 0 - ? right_child - : left_child; + next_i = right_child < length && + gpr_time_cmp(first[left_child]->deadline, + first[right_child]->deadline) < 0 + ? right_child + : left_child; if (gpr_time_cmp(t->deadline, first[next_i]->deadline) >= 0) break; first[i] = first[next_i]; first[i]->heap_index = i; diff --git a/src/core/iomgr/alarm_heap.h b/src/core/iomgr/alarm_heap.h index c5adfc6d31..60db6c991b 100644 --- a/src/core/iomgr/alarm_heap.h +++ b/src/core/iomgr/alarm_heap.h @@ -54,4 +54,4 @@ void grpc_alarm_heap_pop(grpc_alarm_heap *heap); int grpc_alarm_heap_is_empty(grpc_alarm_heap *heap); -#endif /* GRPC_INTERNAL_CORE_IOMGR_ALARM_HEAP_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_ALARM_HEAP_H */ diff --git a/src/core/iomgr/alarm_internal.h b/src/core/iomgr/alarm_internal.h index 0268a01bad..e9f98a3444 100644 --- a/src/core/iomgr/alarm_internal.h +++ b/src/core/iomgr/alarm_internal.h @@ -59,4 +59,4 @@ gpr_timespec grpc_alarm_list_next_timeout(void); void grpc_kick_poller(void); -#endif /* GRPC_INTERNAL_CORE_IOMGR_ALARM_INTERNAL_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_ALARM_INTERNAL_H */ diff --git a/src/core/iomgr/endpoint.c b/src/core/iomgr/endpoint.c index 744fe7656c..8ee14bce9b 100644 --- a/src/core/iomgr/endpoint.c +++ b/src/core/iomgr/endpoint.c @@ -50,7 +50,8 @@ void grpc_endpoint_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) { ep->vtable->add_to_pollset(ep, pollset); } -void grpc_endpoint_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pollset_set) { +void grpc_endpoint_add_to_pollset_set(grpc_endpoint *ep, + grpc_pollset_set *pollset_set) { ep->vtable->add_to_pollset_set(ep, pollset_set); } diff --git a/src/core/iomgr/endpoint.h b/src/core/iomgr/endpoint.h index a2216925f9..ea92a500e8 100644 --- a/src/core/iomgr/endpoint.h +++ b/src/core/iomgr/endpoint.h @@ -103,10 +103,11 @@ void grpc_endpoint_destroy(grpc_endpoint *ep); /* Add an endpoint to a pollset, so that when the pollset is polled, events from this endpoint are considered */ void grpc_endpoint_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset); -void grpc_endpoint_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pollset_set); +void grpc_endpoint_add_to_pollset_set(grpc_endpoint *ep, + grpc_pollset_set *pollset_set); struct grpc_endpoint { const grpc_endpoint_vtable *vtable; }; -#endif /* GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_H */ diff --git a/src/core/iomgr/endpoint_pair.h b/src/core/iomgr/endpoint_pair.h index 25087be0c7..095ec5fcc9 100644 --- a/src/core/iomgr/endpoint_pair.h +++ b/src/core/iomgr/endpoint_pair.h @@ -44,4 +44,4 @@ typedef struct { grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, size_t read_slice_size); -#endif /* GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_PAIR_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_PAIR_H */ diff --git a/src/core/iomgr/endpoint_pair_windows.c b/src/core/iomgr/endpoint_pair_windows.c index e8295df8b3..db9d092dca 100644 --- a/src/core/iomgr/endpoint_pair_windows.c +++ b/src/core/iomgr/endpoint_pair_windows.c @@ -52,21 +52,26 @@ static void create_sockets(SOCKET sv[2]) { SOCKADDR_IN addr; int addr_len = sizeof(addr); - lst_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); + lst_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, + WSA_FLAG_OVERLAPPED); GPR_ASSERT(lst_sock != INVALID_SOCKET); memset(&addr, 0, sizeof(addr)); addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); addr.sin_family = AF_INET; - GPR_ASSERT(bind(lst_sock, (struct sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR); + GPR_ASSERT(bind(lst_sock, (struct sockaddr *)&addr, sizeof(addr)) != + SOCKET_ERROR); GPR_ASSERT(listen(lst_sock, SOMAXCONN) != SOCKET_ERROR); - GPR_ASSERT(getsockname(lst_sock, (struct sockaddr*)&addr, &addr_len) != SOCKET_ERROR); + GPR_ASSERT(getsockname(lst_sock, (struct sockaddr *)&addr, &addr_len) != + SOCKET_ERROR); - cli_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); + cli_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, + WSA_FLAG_OVERLAPPED); GPR_ASSERT(cli_sock != INVALID_SOCKET); - GPR_ASSERT(WSAConnect(cli_sock, (struct sockaddr*)&addr, addr_len, NULL, NULL, NULL, NULL) == 0); - svr_sock = accept(lst_sock, (struct sockaddr*)&addr, &addr_len); + GPR_ASSERT(WSAConnect(cli_sock, (struct sockaddr *)&addr, addr_len, NULL, + NULL, NULL, NULL) == 0); + svr_sock = accept(lst_sock, (struct sockaddr *)&addr, &addr_len); GPR_ASSERT(svr_sock != INVALID_SOCKET); closesocket(lst_sock); @@ -77,7 +82,8 @@ static void create_sockets(SOCKET sv[2]) { sv[0] = svr_sock; } -grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, size_t read_slice_size) { +grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, + size_t read_slice_size) { SOCKET sv[2]; grpc_endpoint_pair p; create_sockets(sv); diff --git a/src/core/iomgr/iocp_windows.c b/src/core/iomgr/iocp_windows.c index 8741241fb8..09a457dd9a 100644 --- a/src/core/iomgr/iocp_windows.c +++ b/src/core/iomgr/iocp_windows.c @@ -65,18 +65,17 @@ static void do_iocp_work() { LPOVERLAPPED overlapped; grpc_winsocket *socket; grpc_winsocket_callback_info *info; - void(*f)(void *, int) = NULL; + void (*f)(void *, int) = NULL; void *opaque = NULL; - success = GetQueuedCompletionStatus(g_iocp, &bytes, - &completion_key, &overlapped, - INFINITE); + success = GetQueuedCompletionStatus(g_iocp, &bytes, &completion_key, + &overlapped, INFINITE); /* success = 0 and overlapped = NULL means the deadline got attained. Which is impossible. since our wait time is +inf */ GPR_ASSERT(success || overlapped); GPR_ASSERT(completion_key && overlapped); if (overlapped == &g_iocp_custom_overlap) { gpr_atm_full_fetch_add(&g_custom_events, -1); - if (completion_key == (ULONG_PTR) &g_iocp_kick_token) { + if (completion_key == (ULONG_PTR)&g_iocp_kick_token) { /* We were awoken from a kick. */ return; } @@ -84,7 +83,7 @@ static void do_iocp_work() { abort(); } - socket = (grpc_winsocket*) completion_key; + socket = (grpc_winsocket *)completion_key; if (overlapped == &socket->write_info.overlapped) { info = &socket->write_info; } else if (overlapped == &socket->read_info.overlapped) { @@ -121,8 +120,7 @@ static void do_iocp_work() { } static void iocp_loop(void *p) { - while (gpr_atm_acq_load(&g_orphans) || - gpr_atm_acq_load(&g_custom_events) || + while (gpr_atm_acq_load(&g_orphans) || gpr_atm_acq_load(&g_custom_events) || !gpr_event_get(&g_shutdown_iocp)) { grpc_maybe_call_delayed_callbacks(NULL, 1); do_iocp_work(); @@ -134,8 +132,8 @@ static void iocp_loop(void *p) { void grpc_iocp_init(void) { gpr_thd_id id; - g_iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, - NULL, (ULONG_PTR)NULL, 0); + g_iocp = + CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)NULL, 0); GPR_ASSERT(g_iocp); gpr_event_init(&g_iocp_done); @@ -147,8 +145,7 @@ void grpc_iocp_kick(void) { BOOL success; gpr_atm_full_fetch_add(&g_custom_events, 1); - success = PostQueuedCompletionStatus(g_iocp, 0, - (ULONG_PTR) &g_iocp_kick_token, + success = PostQueuedCompletionStatus(g_iocp, 0, (ULONG_PTR)&g_iocp_kick_token, &g_iocp_custom_overlap); GPR_ASSERT(success); } @@ -165,8 +162,8 @@ void grpc_iocp_shutdown(void) { void grpc_iocp_add_socket(grpc_winsocket *socket) { HANDLE ret; if (socket->added_to_iocp) return; - ret = CreateIoCompletionPort((HANDLE)socket->socket, - g_iocp, (gpr_uintptr) socket, 0); + ret = CreateIoCompletionPort((HANDLE)socket->socket, g_iocp, + (gpr_uintptr)socket, 0); if (!ret) { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "Unable to add socket to iocp: %s", utf8_message); @@ -189,7 +186,7 @@ void grpc_iocp_socket_orphan(grpc_winsocket *socket) { the callback now. -) The IOCP hasn't completed yet, and we're queuing it for later. */ static void socket_notify_on_iocp(grpc_winsocket *socket, - void(*cb)(void *, int), void *opaque, + void (*cb)(void *, int), void *opaque, grpc_winsocket_callback_info *info) { int run_now = 0; GPR_ASSERT(!info->cb); @@ -206,13 +203,13 @@ static void socket_notify_on_iocp(grpc_winsocket *socket, } void grpc_socket_notify_on_write(grpc_winsocket *socket, - void(*cb)(void *, int), void *opaque) { + void (*cb)(void *, int), void *opaque) { socket_notify_on_iocp(socket, cb, opaque, &socket->write_info); } -void grpc_socket_notify_on_read(grpc_winsocket *socket, - void(*cb)(void *, int), void *opaque) { +void grpc_socket_notify_on_read(grpc_winsocket *socket, void (*cb)(void *, int), + void *opaque) { socket_notify_on_iocp(socket, cb, opaque, &socket->read_info); } -#endif /* GPR_WINSOCK_SOCKET */ +#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/iocp_windows.h b/src/core/iomgr/iocp_windows.h index 9df6476917..ee3847a229 100644 --- a/src/core/iomgr/iocp_windows.h +++ b/src/core/iomgr/iocp_windows.h @@ -44,10 +44,10 @@ void grpc_iocp_shutdown(void); void grpc_iocp_add_socket(grpc_winsocket *); void grpc_iocp_socket_orphan(grpc_winsocket *); -void grpc_socket_notify_on_write(grpc_winsocket *, void(*cb)(void *, int success), - void *opaque); +void grpc_socket_notify_on_write(grpc_winsocket *, + void (*cb)(void *, int success), void *opaque); -void grpc_socket_notify_on_read(grpc_winsocket *, void(*cb)(void *, int success), - void *opaque); +void grpc_socket_notify_on_read(grpc_winsocket *, + void (*cb)(void *, int success), void *opaque); -#endif /* GRPC_INTERNAL_CORE_IOMGR_IOCP_WINDOWS_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_IOCP_WINDOWS_H */ diff --git a/src/core/iomgr/iomgr.h b/src/core/iomgr/iomgr.h index 6d4a82917b..261c17366a 100644 --- a/src/core/iomgr/iomgr.h +++ b/src/core/iomgr/iomgr.h @@ -77,4 +77,4 @@ void grpc_iomgr_add_callback(grpc_iomgr_closure *closure); argument. */ void grpc_iomgr_add_delayed_callback(grpc_iomgr_closure *iocb, int success); -#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_H */ diff --git a/src/core/iomgr/iomgr_internal.h b/src/core/iomgr/iomgr_internal.h index 6c1e0e1799..4cec973ba0 100644 --- a/src/core/iomgr/iomgr_internal.h +++ b/src/core/iomgr/iomgr_internal.h @@ -52,4 +52,4 @@ void grpc_iomgr_unregister_object(grpc_iomgr_object *obj); void grpc_iomgr_platform_init(void); void grpc_iomgr_platform_shutdown(void); -#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H */ diff --git a/src/core/iomgr/iomgr_posix.c b/src/core/iomgr/iomgr_posix.c index 758ae77b86..2425e59941 100644 --- a/src/core/iomgr/iomgr_posix.c +++ b/src/core/iomgr/iomgr_posix.c @@ -51,4 +51,4 @@ void grpc_iomgr_platform_shutdown(void) { grpc_fd_global_shutdown(); } -#endif /* GRPC_POSIX_SOCKET */ +#endif /* GRPC_POSIX_SOCKET */ diff --git a/src/core/iomgr/iomgr_posix.h b/src/core/iomgr/iomgr_posix.h index a404f6433e..716fedb636 100644 --- a/src/core/iomgr/iomgr_posix.h +++ b/src/core/iomgr/iomgr_posix.h @@ -39,4 +39,4 @@ void grpc_pollset_global_init(void); void grpc_pollset_global_shutdown(void); -#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_POSIX_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_POSIX_H */ diff --git a/src/core/iomgr/iomgr_windows.c b/src/core/iomgr/iomgr_windows.c index 74cd5a829b..b49cb87e97 100644 --- a/src/core/iomgr/iomgr_windows.c +++ b/src/core/iomgr/iomgr_windows.c @@ -68,4 +68,4 @@ void grpc_iomgr_platform_shutdown(void) { winsock_shutdown(); } -#endif /* GRPC_WINSOCK_SOCKET */ +#endif /* GRPC_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/pollset_multipoller_with_epoll.c b/src/core/iomgr/pollset_multipoller_with_epoll.c index 1320c64579..5ea9dd2101 100644 --- a/src/core/iomgr/pollset_multipoller_with_epoll.c +++ b/src/core/iomgr/pollset_multipoller_with_epoll.c @@ -234,8 +234,7 @@ static void multipoll_with_epoll_pollset_destroy(grpc_pollset *pollset) { } static const grpc_pollset_vtable multipoll_with_epoll_pollset = { - multipoll_with_epoll_pollset_add_fd, - multipoll_with_epoll_pollset_del_fd, + multipoll_with_epoll_pollset_add_fd, multipoll_with_epoll_pollset_del_fd, multipoll_with_epoll_pollset_maybe_work, multipoll_with_epoll_pollset_finish_shutdown, multipoll_with_epoll_pollset_destroy}; diff --git a/src/core/iomgr/pollset_multipoller_with_poll_posix.c b/src/core/iomgr/pollset_multipoller_with_poll_posix.c index b5b2d7534d..001fcecf76 100644 --- a/src/core/iomgr/pollset_multipoller_with_poll_posix.c +++ b/src/core/iomgr/pollset_multipoller_with_poll_posix.c @@ -74,7 +74,7 @@ static void multipoll_with_poll_pollset_add_fd(grpc_pollset *pollset, } h->fds[h->fd_count++] = fd; GRPC_FD_REF(fd, "multipoller"); -exit: +exit: if (and_unlock_pollset) { gpr_mu_unlock(&pollset->mu); } @@ -202,8 +202,7 @@ static void multipoll_with_poll_pollset_destroy(grpc_pollset *pollset) { } static const grpc_pollset_vtable multipoll_with_poll_pollset = { - multipoll_with_poll_pollset_add_fd, - multipoll_with_poll_pollset_del_fd, + multipoll_with_poll_pollset_add_fd, multipoll_with_poll_pollset_del_fd, multipoll_with_poll_pollset_maybe_work, multipoll_with_poll_pollset_finish_shutdown, multipoll_with_poll_pollset_destroy}; diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c index d3a9193af1..a01f9ff727 100644 --- a/src/core/iomgr/pollset_posix.c +++ b/src/core/iomgr/pollset_posix.c @@ -140,10 +140,10 @@ void grpc_pollset_init(grpc_pollset *pollset) { void grpc_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) { gpr_mu_lock(&pollset->mu); pollset->vtable->add_fd(pollset, fd, 1); - /* the following (enabled only in debug) will reacquire and then release - our lock - meaning that if the unlocking flag passed to del_fd above is - not respected, the code will deadlock (in a way that we have a chance of - debugging) */ +/* the following (enabled only in debug) will reacquire and then release + our lock - meaning that if the unlocking flag passed to del_fd above is + not respected, the code will deadlock (in a way that we have a chance of + debugging) */ #ifndef NDEBUG gpr_mu_lock(&pollset->mu); gpr_mu_unlock(&pollset->mu); @@ -153,10 +153,10 @@ void grpc_pollset_add_fd(grpc_pollset *pollset, grpc_fd *fd) { void grpc_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) { gpr_mu_lock(&pollset->mu); pollset->vtable->del_fd(pollset, fd, 1); - /* the following (enabled only in debug) will reacquire and then release - our lock - meaning that if the unlocking flag passed to del_fd above is - not respected, the code will deadlock (in a way that we have a chance of - debugging) */ +/* the following (enabled only in debug) will reacquire and then release + our lock - meaning that if the unlocking flag passed to del_fd above is + not respected, the code will deadlock (in a way that we have a chance of + debugging) */ #ifndef NDEBUG gpr_mu_lock(&pollset->mu); gpr_mu_unlock(&pollset->mu); diff --git a/src/core/iomgr/pollset_posix.h b/src/core/iomgr/pollset_posix.h index 1c1b736193..a3ea353de6 100644 --- a/src/core/iomgr/pollset_posix.h +++ b/src/core/iomgr/pollset_posix.h @@ -102,7 +102,8 @@ void grpc_kick_drain(grpc_pollset *p); - longer than a millisecond polls are rounded up to the next nearest millisecond to avoid spinning - infinite timeouts are converted to -1 */ -int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline, gpr_timespec now); +int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline, + gpr_timespec now); /* turn a pollset into a multipoller: platform specific */ typedef void (*grpc_platform_become_multipoller_type)(grpc_pollset *pollset, diff --git a/src/core/iomgr/pollset_windows.c b/src/core/iomgr/pollset_windows.c index 22dc5891c3..8710395ab3 100644 --- a/src/core/iomgr/pollset_windows.c +++ b/src/core/iomgr/pollset_windows.c @@ -56,8 +56,7 @@ static grpc_pollset_worker *pop_front_worker(grpc_pollset *p) { grpc_pollset_worker *w = p->root_worker.next; remove_worker(p, w); return w; - } - else { + } else { return NULL; } } @@ -100,7 +99,8 @@ void grpc_pollset_destroy(grpc_pollset *pollset) { gpr_mu_destroy(&pollset->mu); } -int grpc_pollset_work(grpc_pollset *pollset, grpc_pollset_worker *worker, gpr_timespec deadline) { +int grpc_pollset_work(grpc_pollset *pollset, grpc_pollset_worker *worker, + gpr_timespec deadline) { gpr_timespec now; int added_worker = 0; now = gpr_now(GPR_CLOCK_MONOTONIC); @@ -134,8 +134,8 @@ void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) { if (specific_worker != NULL) { if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) { for (specific_worker = p->root_worker.next; - specific_worker != &p->root_worker; - specific_worker = specific_worker->next) { + specific_worker != &p->root_worker; + specific_worker = specific_worker->next) { gpr_cv_signal(&specific_worker->cv); } p->kicked_without_pollers = 1; diff --git a/src/core/iomgr/resolve_address.h b/src/core/iomgr/resolve_address.h index 8f1d7a22bb..cc1bd428b0 100644 --- a/src/core/iomgr/resolve_address.h +++ b/src/core/iomgr/resolve_address.h @@ -66,4 +66,4 @@ void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addresses); grpc_resolved_addresses *grpc_blocking_resolve_address( const char *addr, const char *default_port); -#endif /* GRPC_INTERNAL_CORE_IOMGR_RESOLVE_ADDRESS_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_RESOLVE_ADDRESS_H */ diff --git a/src/core/iomgr/resolve_address_posix.c b/src/core/iomgr/resolve_address_posix.c index dbf884c769..ce6972b797 100644 --- a/src/core/iomgr/resolve_address_posix.c +++ b/src/core/iomgr/resolve_address_posix.c @@ -105,10 +105,7 @@ grpc_resolved_addresses *grpc_blocking_resolve_address( s = getaddrinfo(host, port, &hints, &result); if (s != 0) { /* Retry if well-known service name is recognized */ - char *svc[][2] = { - {"http", "80"}, - {"https", "443"} - }; + char *svc[][2] = {{"http", "80"}, {"https", "443"}}; int i; for (i = 0; i < (int)(sizeof(svc) / sizeof(svc[0])); i++) { if (strcmp(port, svc[i][0]) == 0) { diff --git a/src/core/iomgr/sockaddr.h b/src/core/iomgr/sockaddr.h index 7528db73b8..e41e1ec6b4 100644 --- a/src/core/iomgr/sockaddr.h +++ b/src/core/iomgr/sockaddr.h @@ -44,4 +44,4 @@ #include "src/core/iomgr/sockaddr_posix.h" #endif -#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_H */ diff --git a/src/core/iomgr/sockaddr_posix.h b/src/core/iomgr/sockaddr_posix.h index 2a3d932f70..388abb3306 100644 --- a/src/core/iomgr/sockaddr_posix.h +++ b/src/core/iomgr/sockaddr_posix.h @@ -41,4 +41,4 @@ #include <netdb.h> #include <unistd.h> -#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_POSIX_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_POSIX_H */ diff --git a/src/core/iomgr/sockaddr_utils.c b/src/core/iomgr/sockaddr_utils.c index 65ec1f94ac..efdc480365 100644 --- a/src/core/iomgr/sockaddr_utils.c +++ b/src/core/iomgr/sockaddr_utils.c @@ -206,7 +206,8 @@ int grpc_sockaddr_get_port(const struct sockaddr *addr) { case AF_UNIX: return 1; default: - gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_get_port", addr->sa_family); + gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_get_port", + addr->sa_family); return 0; } } @@ -220,7 +221,8 @@ int grpc_sockaddr_set_port(const struct sockaddr *addr, int port) { ((struct sockaddr_in6 *)addr)->sin6_port = htons(port); return 1; default: - gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_set_port", addr->sa_family); + gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_set_port", + addr->sa_family); return 0; } } diff --git a/src/core/iomgr/sockaddr_utils.h b/src/core/iomgr/sockaddr_utils.h index 99f1ed54da..6f7a279900 100644 --- a/src/core/iomgr/sockaddr_utils.h +++ b/src/core/iomgr/sockaddr_utils.h @@ -86,4 +86,4 @@ int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr, char *grpc_sockaddr_to_uri(const struct sockaddr *addr); -#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_UTILS_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_UTILS_H */ diff --git a/src/core/iomgr/sockaddr_win32.h b/src/core/iomgr/sockaddr_win32.h index be55db805a..fe2be99145 100644 --- a/src/core/iomgr/sockaddr_win32.h +++ b/src/core/iomgr/sockaddr_win32.h @@ -43,4 +43,4 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); #endif -#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_WIN32_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_WIN32_H */ diff --git a/src/core/iomgr/socket_utils_posix.h b/src/core/iomgr/socket_utils_posix.h index d2a315b462..d330d1986e 100644 --- a/src/core/iomgr/socket_utils_posix.h +++ b/src/core/iomgr/socket_utils_posix.h @@ -110,4 +110,4 @@ extern int grpc_forbid_dualstack_sockets_for_testing; int grpc_create_dualstack_socket(const struct sockaddr *addr, int type, int protocol, grpc_dualstack_mode *dsmode); -#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKET_UTILS_POSIX_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKET_UTILS_POSIX_H */ diff --git a/src/core/iomgr/socket_windows.c b/src/core/iomgr/socket_windows.c index f6ddfff0ad..7d8421376b 100644 --- a/src/core/iomgr/socket_windows.c +++ b/src/core/iomgr/socket_windows.c @@ -106,4 +106,4 @@ void grpc_winsocket_destroy(grpc_winsocket *winsocket) { gpr_free(winsocket); } -#endif /* GPR_WINSOCK_SOCKET */ +#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/socket_windows.h b/src/core/iomgr/socket_windows.h index 346fde8edd..ecf2530173 100644 --- a/src/core/iomgr/socket_windows.h +++ b/src/core/iomgr/socket_windows.h @@ -54,7 +54,7 @@ typedef struct grpc_winsocket_callback_info { OVERLAPPED overlapped; /* The callback information for the pending operation. May be empty if the caller hasn't registered a callback yet. */ - void(*cb)(void *opaque, int success); + void (*cb)(void *opaque, int success); void *opaque; /* A boolean to describe if the IO Completion Port got a notification for that operation. This will happen if the operation completed before the @@ -118,4 +118,4 @@ void grpc_winsocket_orphan(grpc_winsocket *socket); or by grpc_winsocket_orphan if there's no pending operation. */ void grpc_winsocket_destroy(grpc_winsocket *socket); -#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKET_WINDOWS_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKET_WINDOWS_H */ diff --git a/src/core/iomgr/tcp_client.h b/src/core/iomgr/tcp_client.h index 0fa08b52b0..8ad9b818e1 100644 --- a/src/core/iomgr/tcp_client.h +++ b/src/core/iomgr/tcp_client.h @@ -41,7 +41,7 @@ /* Asynchronously connect to an address (specified as (addr, len)), and call cb with arg and the completed connection when done (or call cb with arg and - NULL on failure). + NULL on failure). interested_parties points to a set of pollsets that would be interested in this connection being established (in order to continue their work) */ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *tcp), diff --git a/src/core/iomgr/tcp_client_posix.c b/src/core/iomgr/tcp_client_posix.c index 9572ce5980..66027f87a0 100644 --- a/src/core/iomgr/tcp_client_posix.c +++ b/src/core/iomgr/tcp_client_posix.c @@ -264,7 +264,8 @@ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep), ac->write_closure.cb_arg = ac; gpr_mu_lock(&ac->mu); - grpc_alarm_init(&ac->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), + grpc_alarm_init(&ac->alarm, + gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), tc_on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC)); grpc_fd_notify_on_write(ac->fd, &ac->write_closure); gpr_mu_unlock(&ac->mu); diff --git a/src/core/iomgr/tcp_posix.c b/src/core/iomgr/tcp_posix.c index 24fee0596f..360e6ebd8c 100644 --- a/src/core/iomgr/tcp_posix.c +++ b/src/core/iomgr/tcp_posix.c @@ -572,7 +572,8 @@ static void grpc_tcp_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) { grpc_pollset_add_fd(pollset, tcp->em_fd); } -static void grpc_tcp_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pollset_set) { +static void grpc_tcp_add_to_pollset_set(grpc_endpoint *ep, + grpc_pollset_set *pollset_set) { grpc_tcp *tcp = (grpc_tcp *)ep; grpc_pollset_set_add_fd(pollset_set, tcp->em_fd); } diff --git a/src/core/iomgr/tcp_posix.h b/src/core/iomgr/tcp_posix.h index d752feaeea..40b3ae2679 100644 --- a/src/core/iomgr/tcp_posix.h +++ b/src/core/iomgr/tcp_posix.h @@ -56,4 +56,4 @@ extern int grpc_tcp_trace; grpc_endpoint *grpc_tcp_create(grpc_fd *fd, size_t read_slice_size, const char *peer_string); -#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_POSIX_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_POSIX_H */ diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c index 0adbe9507c..d0478d3604 100644 --- a/src/core/iomgr/tcp_server_windows.c +++ b/src/core/iomgr/tcp_server_windows.c @@ -79,7 +79,8 @@ struct grpc_tcp_server { /* active port count: how many ports are actually still listening */ int active_ports; - /* number of iomgr callbacks that have been explicitly scheduled during shutdown */ + /* number of iomgr callbacks that have been explicitly scheduled during + * shutdown */ int iomgr_callbacks_pending; /* all listening ports */ @@ -292,7 +293,7 @@ static void on_accept(void *arg, int from_iocp) { and act accordingly. */ transfered_bytes = 0; wsa_success = WSAGetOverlappedResult(sock, &info->overlapped, - &transfered_bytes, FALSE, &flags); + &transfered_bytes, FALSE, &flags); if (!wsa_success) { if (sp->shutting_down) { /* During the shutdown case, we ARE expecting an error. So that's well, @@ -309,16 +310,15 @@ static void on_accept(void *arg, int from_iocp) { if (!sp->shutting_down) { peer_name_string = NULL; err = setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, - (char *)&sp->socket->socket, - sizeof(sp->socket->socket)); + (char *)&sp->socket->socket, sizeof(sp->socket->socket)); if (err) { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "setsockopt error: %s", utf8_message); gpr_free(utf8_message); } - err = getpeername(sock, (struct sockaddr*)&peer_name, &peer_name_len); + err = getpeername(sock, (struct sockaddr *)&peer_name, &peer_name_len); if (!err) { - peer_name_string = grpc_sockaddr_to_uri((struct sockaddr*)&peer_name); + peer_name_string = grpc_sockaddr_to_uri((struct sockaddr *)&peer_name); } else { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "getpeername error: %s", utf8_message); diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c index 89aa741470..123f46d71d 100644 --- a/src/core/iomgr/tcp_windows.c +++ b/src/core/iomgr/tcp_windows.c @@ -55,24 +55,22 @@ static int set_non_block(SOCKET sock) { int status; unsigned long param = 1; DWORD ret; - status = WSAIoctl(sock, FIONBIO, ¶m, sizeof(param), NULL, 0, &ret, - NULL, NULL); + status = + WSAIoctl(sock, FIONBIO, ¶m, sizeof(param), NULL, 0, &ret, NULL, NULL); return status == 0; } static int set_dualstack(SOCKET sock) { int status; unsigned long param = 0; - status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, - (const char *) ¶m, sizeof(param)); + status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)¶m, + sizeof(param)); return status == 0; } int grpc_tcp_prepare_socket(SOCKET sock) { - if (!set_non_block(sock)) - return 0; - if (!set_dualstack(sock)) - return 0; + if (!set_non_block(sock)) return 0; + if (!set_dualstack(sock)) return 0; return 1; } @@ -100,9 +98,7 @@ typedef struct grpc_tcp { char *peer_string; } grpc_tcp; -static void tcp_ref(grpc_tcp *tcp) { - gpr_ref(&tcp->refcount); -} +static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); } static void tcp_unref(grpc_tcp *tcp) { if (gpr_unref(&tcp->refcount)) { @@ -116,7 +112,7 @@ static void tcp_unref(grpc_tcp *tcp) { /* Asynchronous callback from the IOCP, or the background thread. */ static void on_read(void *tcpp, int from_iocp) { - grpc_tcp *tcp = (grpc_tcp *) tcpp; + grpc_tcp *tcp = (grpc_tcp *)tcpp; grpc_winsocket *socket = tcp->socket; gpr_slice sub; gpr_slice *slice = NULL; @@ -175,9 +171,9 @@ static void on_read(void *tcpp, int from_iocp) { cb(opaque, slice, nslices, status); } -static void win_notify_on_read(grpc_endpoint *ep, - grpc_endpoint_read_cb cb, void *arg) { - grpc_tcp *tcp = (grpc_tcp *) ep; +static void win_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb, + void *arg) { + grpc_tcp *tcp = (grpc_tcp *)ep; grpc_winsocket *handle = tcp->socket; grpc_winsocket_callback_info *info = &handle->read_info; int status; @@ -201,8 +197,8 @@ static void win_notify_on_read(grpc_endpoint *ep, buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice); /* First let's try a synchronous, non-blocking read. */ - status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, - NULL, NULL); + status = + WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, NULL, NULL); info->wsa_error = status == 0 ? 0 : WSAGetLastError(); /* Did we get data immediately ? Yay. */ @@ -232,7 +228,7 @@ static void win_notify_on_read(grpc_endpoint *ep, /* Asynchronous callback from the IOCP, or the background thread. */ static void on_write(void *tcpp, int from_iocp) { - grpc_tcp *tcp = (grpc_tcp *) tcpp; + grpc_tcp *tcp = (grpc_tcp *)tcpp; grpc_winsocket *handle = tcp->socket; grpc_winsocket_callback_info *info = &handle->write_info; grpc_endpoint_cb_status status = GRPC_ENDPOINT_CB_OK; @@ -286,7 +282,7 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep, gpr_slice *slices, size_t nslices, grpc_endpoint_write_cb cb, void *arg) { - grpc_tcp *tcp = (grpc_tcp *) ep; + grpc_tcp *tcp = (grpc_tcp *)ep; grpc_winsocket *socket = tcp->socket; grpc_winsocket_callback_info *info = &socket->write_info; unsigned i; @@ -309,7 +305,7 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep, gpr_slice_buffer_addn(&tcp->write_slices, slices, nslices); if (tcp->write_slices.count > GPR_ARRAY_SIZE(local_buffers)) { - buffers = (WSABUF *) gpr_malloc(sizeof(WSABUF) * tcp->write_slices.count); + buffers = (WSABUF *)gpr_malloc(sizeof(WSABUF) * tcp->write_slices.count); allocated = buffers; } @@ -370,15 +366,15 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep, static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *ps) { grpc_tcp *tcp; - (void) ps; - tcp = (grpc_tcp *) ep; + (void)ps; + tcp = (grpc_tcp *)ep; grpc_iocp_add_socket(tcp->socket); } static void win_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pss) { grpc_tcp *tcp; - (void) pss; - tcp = (grpc_tcp *) ep; + (void)pss; + tcp = (grpc_tcp *)ep; grpc_iocp_add_socket(tcp->socket); } @@ -389,7 +385,7 @@ static void win_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pss) { callback will happen from another thread, so we need to protect against concurrent access of the data structure in that regard. */ static void win_shutdown(grpc_endpoint *ep) { - grpc_tcp *tcp = (grpc_tcp *) ep; + grpc_tcp *tcp = (grpc_tcp *)ep; int extra_refs = 0; gpr_mu_lock(&tcp->mu); /* At that point, what may happen is that we're already inside the IOCP @@ -401,7 +397,7 @@ static void win_shutdown(grpc_endpoint *ep) { } static void win_destroy(grpc_endpoint *ep) { - grpc_tcp *tcp = (grpc_tcp *) ep; + grpc_tcp *tcp = (grpc_tcp *)ep; tcp_unref(tcp); } @@ -410,13 +406,12 @@ static char *win_get_peer(grpc_endpoint *ep) { return gpr_strdup(tcp->peer_string); } -static grpc_endpoint_vtable vtable = {win_notify_on_read, win_write, - win_add_to_pollset, win_add_to_pollset_set, - win_shutdown, win_destroy, - win_get_peer}; +static grpc_endpoint_vtable vtable = { + win_notify_on_read, win_write, win_add_to_pollset, win_add_to_pollset_set, + win_shutdown, win_destroy, win_get_peer}; grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) { - grpc_tcp *tcp = (grpc_tcp *) gpr_malloc(sizeof(grpc_tcp)); + grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp)); memset(tcp, 0, sizeof(grpc_tcp)); tcp->base.vtable = &vtable; tcp->socket = socket; @@ -427,4 +422,4 @@ grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) { return &tcp->base; } -#endif /* GPR_WINSOCK_SOCKET */ +#endif /* GPR_WINSOCK_SOCKET */ diff --git a/src/core/iomgr/tcp_windows.h b/src/core/iomgr/tcp_windows.h index 7e301db250..deb3e48293 100644 --- a/src/core/iomgr/tcp_windows.h +++ b/src/core/iomgr/tcp_windows.h @@ -54,4 +54,4 @@ grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string); int grpc_tcp_prepare_socket(SOCKET sock); -#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_WINDOWS_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_WINDOWS_H */ diff --git a/src/core/iomgr/time_averaged_stats.h b/src/core/iomgr/time_averaged_stats.h index 13894b2640..e6dec1b4cd 100644 --- a/src/core/iomgr/time_averaged_stats.h +++ b/src/core/iomgr/time_averaged_stats.h @@ -85,4 +85,4 @@ void grpc_time_averaged_stats_add_sample(grpc_time_averaged_stats *stats, value. */ double grpc_time_averaged_stats_update_average(grpc_time_averaged_stats *stats); -#endif /* GRPC_INTERNAL_CORE_IOMGR_TIME_AVERAGED_STATS_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_TIME_AVERAGED_STATS_H */ diff --git a/src/core/iomgr/udp_server.c b/src/core/iomgr/udp_server.c index db0aef8120..16482c08f7 100644 --- a/src/core/iomgr/udp_server.c +++ b/src/core/iomgr/udp_server.c @@ -232,11 +232,11 @@ static int prepare_socket(int fd, const struct sockaddr *addr, int addr_len) { } get_local_ip = 1; - rc = setsockopt(fd, IPPROTO_IP, IP_PKTINFO, - &get_local_ip, sizeof(get_local_ip)); + rc = setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &get_local_ip, + sizeof(get_local_ip)); if (rc == 0 && addr->sa_family == AF_INET6) { - rc = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, - &get_local_ip, sizeof(get_local_ip)); + rc = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &get_local_ip, + sizeof(get_local_ip)); } if (bind(fd, addr, addr_len) < 0) { @@ -317,8 +317,8 @@ static int add_socket_to_server(grpc_udp_server *s, int fd, return port; } -int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, - int addr_len, grpc_udp_server_read_cb read_cb) { +int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, int addr_len, + grpc_udp_server_read_cb read_cb) { int allocated_port1 = -1; int allocated_port2 = -1; unsigned i; diff --git a/src/core/iomgr/wakeup_fd_eventfd.c b/src/core/iomgr/wakeup_fd_eventfd.c index 52912235f8..08fdc74f17 100644 --- a/src/core/iomgr/wakeup_fd_eventfd.c +++ b/src/core/iomgr/wakeup_fd_eventfd.c @@ -75,8 +75,7 @@ static int eventfd_check_availability(void) { } const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable = { - eventfd_create, eventfd_consume, eventfd_wakeup, eventfd_destroy, - eventfd_check_availability -}; + eventfd_create, eventfd_consume, eventfd_wakeup, eventfd_destroy, + eventfd_check_availability}; #endif /* GPR_LINUX_EVENTFD */ diff --git a/src/core/iomgr/wakeup_fd_nospecial.c b/src/core/iomgr/wakeup_fd_nospecial.c index c1038bf379..78d763c103 100644 --- a/src/core/iomgr/wakeup_fd_nospecial.c +++ b/src/core/iomgr/wakeup_fd_nospecial.c @@ -43,12 +43,9 @@ #include "src/core/iomgr/wakeup_fd_posix.h" #include <stddef.h> -static int check_availability_invalid(void) { - return 0; -} +static int check_availability_invalid(void) { return 0; } const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable = { - NULL, NULL, NULL, NULL, check_availability_invalid -}; + NULL, NULL, NULL, NULL, check_availability_invalid}; -#endif /* GPR_POSIX_NO_SPECIAL_WAKEUP_FD */ +#endif /* GPR_POSIX_NO_SPECIAL_WAKEUP_FD */ diff --git a/src/core/iomgr/wakeup_fd_pipe.c b/src/core/iomgr/wakeup_fd_pipe.c index 9fc4ee2388..bd643e8061 100644 --- a/src/core/iomgr/wakeup_fd_pipe.c +++ b/src/core/iomgr/wakeup_fd_pipe.c @@ -94,4 +94,4 @@ const grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable = { pipe_init, pipe_consume, pipe_wakeup, pipe_destroy, pipe_check_availability}; -#endif /* GPR_POSIX_WAKUP_FD */ +#endif /* GPR_POSIX_WAKUP_FD */ diff --git a/src/core/iomgr/wakeup_fd_pipe.h b/src/core/iomgr/wakeup_fd_pipe.h index aa8f977ddb..01a13a97c0 100644 --- a/src/core/iomgr/wakeup_fd_pipe.h +++ b/src/core/iomgr/wakeup_fd_pipe.h @@ -38,4 +38,4 @@ extern grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable; -#endif /* GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_PIPE_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_PIPE_H */ diff --git a/src/core/iomgr/wakeup_fd_posix.c b/src/core/iomgr/wakeup_fd_posix.c index e48f5223fa..d09fb78d12 100644 --- a/src/core/iomgr/wakeup_fd_posix.c +++ b/src/core/iomgr/wakeup_fd_posix.c @@ -53,9 +53,7 @@ void grpc_wakeup_fd_global_init_force_fallback(void) { wakeup_fd_vtable = &grpc_pipe_wakeup_fd_vtable; } -void grpc_wakeup_fd_global_destroy(void) { - wakeup_fd_vtable = NULL; -} +void grpc_wakeup_fd_global_destroy(void) { wakeup_fd_vtable = NULL; } void grpc_wakeup_fd_init(grpc_wakeup_fd *fd_info) { wakeup_fd_vtable->init(fd_info); @@ -73,4 +71,4 @@ void grpc_wakeup_fd_destroy(grpc_wakeup_fd *fd_info) { wakeup_fd_vtable->destroy(fd_info); } -#endif /* GPR_POSIX_WAKEUP_FD */ +#endif /* GPR_POSIX_WAKEUP_FD */ diff --git a/src/core/iomgr/wakeup_fd_posix.h b/src/core/iomgr/wakeup_fd_posix.h index a4da4df51f..b6c086900d 100644 --- a/src/core/iomgr/wakeup_fd_posix.h +++ b/src/core/iomgr/wakeup_fd_posix.h @@ -96,4 +96,4 @@ void grpc_wakeup_fd_destroy(grpc_wakeup_fd *fd_info); * wakeup_fd_nospecial.c if no such implementation exists. */ extern const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable; -#endif /* GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_POSIX_H */ +#endif /* GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_POSIX_H */ diff --git a/src/core/json/json.h b/src/core/json/json.h index cac18ad885..573584bf6f 100644 --- a/src/core/json/json.h +++ b/src/core/json/json.h @@ -85,4 +85,4 @@ char* grpc_json_dump_to_string(grpc_json* json, int indent); grpc_json* grpc_json_create(grpc_json_type type); void grpc_json_destroy(grpc_json* json); -#endif /* GRPC_INTERNAL_CORE_JSON_JSON_H */ +#endif /* GRPC_INTERNAL_CORE_JSON_JSON_H */ diff --git a/src/core/json/json_common.h b/src/core/json/json_common.h index 84bf375916..481695b38b 100644 --- a/src/core/json/json_common.h +++ b/src/core/json/json_common.h @@ -46,4 +46,4 @@ typedef enum { GRPC_JSON_TOP_LEVEL } grpc_json_type; -#endif /* GRPC_INTERNAL_CORE_JSON_JSON_COMMON_H */ +#endif /* GRPC_INTERNAL_CORE_JSON_JSON_COMMON_H */ diff --git a/src/core/json/json_reader.c b/src/core/json/json_reader.c index c14094c290..c22d4edd47 100644 --- a/src/core/json/json_reader.c +++ b/src/core/json/json_reader.c @@ -42,27 +42,26 @@ static void json_reader_string_clear(grpc_json_reader* reader) { } static void json_reader_string_add_char(grpc_json_reader* reader, - gpr_uint32 c) { + gpr_uint32 c) { reader->vtable->string_add_char(reader->userdata, c); } static void json_reader_string_add_utf32(grpc_json_reader* reader, - gpr_uint32 utf32) { + gpr_uint32 utf32) { reader->vtable->string_add_utf32(reader->userdata, utf32); } -static gpr_uint32 - grpc_json_reader_read_char(grpc_json_reader* reader) { +static gpr_uint32 grpc_json_reader_read_char(grpc_json_reader* reader) { return reader->vtable->read_char(reader->userdata); } static void json_reader_container_begins(grpc_json_reader* reader, - grpc_json_type type) { + grpc_json_type type) { reader->vtable->container_begins(reader->userdata, type); } -static grpc_json_type - grpc_json_reader_container_ends(grpc_json_reader* reader) { +static grpc_json_type grpc_json_reader_container_ends( + grpc_json_reader* reader) { return reader->vtable->container_ends(reader->userdata); } @@ -101,8 +100,9 @@ void grpc_json_reader_init(grpc_json_reader* reader, } int grpc_json_reader_is_complete(grpc_json_reader* reader) { - return ((reader->depth == 0) && ((reader->state == GRPC_JSON_STATE_END) || - (reader->state == GRPC_JSON_STATE_VALUE_END))); + return ((reader->depth == 0) && + ((reader->state == GRPC_JSON_STATE_END) || + (reader->state == GRPC_JSON_STATE_VALUE_END))); } grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { @@ -143,7 +143,8 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { case GRPC_JSON_STATE_OBJECT_KEY_STRING: case GRPC_JSON_STATE_VALUE_STRING: if (c != ' ') return GRPC_JSON_PARSE_ERROR; - if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR; + if (reader->unicode_high_surrogate != 0) + return GRPC_JSON_PARSE_ERROR; json_reader_string_add_char(reader, c); break; @@ -169,7 +170,8 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { switch (reader->state) { case GRPC_JSON_STATE_OBJECT_KEY_STRING: case GRPC_JSON_STATE_VALUE_STRING: - if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR; + if (reader->unicode_high_surrogate != 0) + return GRPC_JSON_PARSE_ERROR; json_reader_string_add_char(reader, c); break; @@ -253,7 +255,8 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { /* This is the \\ case. */ case GRPC_JSON_STATE_STRING_ESCAPE: - if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR; + if (reader->unicode_high_surrogate != 0) + return GRPC_JSON_PARSE_ERROR; json_reader_string_add_char(reader, '\\'); if (reader->escaped_string_was_key) { reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING; @@ -276,7 +279,8 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { break; case GRPC_JSON_STATE_OBJECT_KEY_STRING: - if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR; + if (reader->unicode_high_surrogate != 0) + return GRPC_JSON_PARSE_ERROR; if (c == '"') { reader->state = GRPC_JSON_STATE_OBJECT_KEY_END; json_reader_set_key(reader); @@ -288,7 +292,8 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { break; case GRPC_JSON_STATE_VALUE_STRING: - if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR; + if (reader->unicode_high_surrogate != 0) + return GRPC_JSON_PARSE_ERROR; if (c == '"') { reader->state = GRPC_JSON_STATE_VALUE_END; json_reader_set_string(reader); @@ -438,7 +443,8 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) { if (reader->unicode_high_surrogate == 0) return GRPC_JSON_PARSE_ERROR; utf32 = 0x10000; - utf32 += (gpr_uint32)((reader->unicode_high_surrogate - 0xd800) * 0x400); + utf32 += (gpr_uint32)( + (reader->unicode_high_surrogate - 0xd800) * 0x400); utf32 += (gpr_uint32)(reader->unicode_char - 0xdc00); json_reader_string_add_utf32(reader, utf32); reader->unicode_high_surrogate = 0; diff --git a/src/core/json/json_reader.h b/src/core/json/json_reader.h index b1a5ace8fb..4d5487f790 100644 --- a/src/core/json/json_reader.h +++ b/src/core/json/json_reader.h @@ -157,4 +157,4 @@ void grpc_json_reader_init(grpc_json_reader* reader, */ int grpc_json_reader_is_complete(grpc_json_reader* reader); -#endif /* GRPC_INTERNAL_CORE_JSON_JSON_READER_H */ +#endif /* GRPC_INTERNAL_CORE_JSON_JSON_READER_H */ diff --git a/src/core/json/json_string.c b/src/core/json/json_string.c index 03c1099167..e6622ec461 100644 --- a/src/core/json/json_string.c +++ b/src/core/json/json_string.c @@ -73,7 +73,6 @@ typedef struct { size_t allocated; } json_writer_userdata; - /* This function checks if there's enough space left in the output buffer, * and will enlarge it if necessary. We're only allocating chunks of 256 * bytes at a time (or multiples thereof). @@ -97,8 +96,8 @@ static void json_writer_output_char(void* userdata, char c) { state->free_space--; } -static void json_writer_output_string_with_len(void* userdata, - const char* str, size_t len) { +static void json_writer_output_string_with_len(void* userdata, const char* str, + size_t len) { json_writer_userdata* state = userdata; json_writer_output_check(userdata, len); memcpy(state->output + state->string_len, str, len); @@ -106,8 +105,7 @@ static void json_writer_output_string_with_len(void* userdata, state->free_space -= len; } -static void json_writer_output_string(void* userdata, - const char* str) { +static void json_writer_output_string(void* userdata, const char* str) { size_t len = strlen(str); json_writer_output_string_with_len(userdata, str, len); } @@ -184,8 +182,7 @@ static gpr_uint32 json_reader_read_char(void* userdata) { /* Helper function to create a new grpc_json object and link it into * our tree-in-progress inside our opaque structure. */ -static grpc_json* json_create_and_link(void* userdata, - grpc_json_type type) { +static grpc_json* json_create_and_link(void* userdata, grpc_json_type type) { json_reader_userdata* state = userdata; grpc_json* json = grpc_json_create(type); @@ -201,7 +198,7 @@ static grpc_json* json_create_and_link(void* userdata, json->parent->child = json; } if (json->parent->type == GRPC_JSON_OBJECT) { - json->key = (char*) state->key; + json->key = (char*)state->key; } } if (!state->top) { @@ -261,13 +258,13 @@ static void json_reader_set_key(void* userdata) { static void json_reader_set_string(void* userdata) { json_reader_userdata* state = userdata; grpc_json* json = json_create_and_link(userdata, GRPC_JSON_STRING); - json->value = (char*) state->string; + json->value = (char*)state->string; } static int json_reader_set_number(void* userdata) { json_reader_userdata* state = userdata; grpc_json* json = json_create_and_link(userdata, GRPC_JSON_NUMBER); - json->value = (char*) state->string; + json->value = (char*)state->string; return 1; } @@ -287,32 +284,25 @@ static void json_reader_set_null(void* userdata) { } static grpc_json_reader_vtable reader_vtable = { - json_reader_string_clear, - json_reader_string_add_char, - json_reader_string_add_utf32, - json_reader_read_char, - json_reader_container_begins, - json_reader_container_ends, - json_reader_set_key, - json_reader_set_string, - json_reader_set_number, - json_reader_set_true, - json_reader_set_false, - json_reader_set_null -}; + json_reader_string_clear, json_reader_string_add_char, + json_reader_string_add_utf32, json_reader_read_char, + json_reader_container_begins, json_reader_container_ends, + json_reader_set_key, json_reader_set_string, + json_reader_set_number, json_reader_set_true, + json_reader_set_false, json_reader_set_null}; /* And finally, let's define our public API. */ grpc_json* grpc_json_parse_string_with_len(char* input, size_t size) { grpc_json_reader reader; json_reader_userdata state; - grpc_json *json = NULL; + grpc_json* json = NULL; grpc_json_reader_status status; if (!input) return NULL; state.top = state.current_container = state.current_value = NULL; state.string = state.key = NULL; - state.string_ptr = state.input = (gpr_uint8*) input; + state.string_ptr = state.input = (gpr_uint8*)input; state.remaining_input = size; grpc_json_reader_init(&reader, &reader_vtable, &state); @@ -333,8 +323,8 @@ grpc_json* grpc_json_parse_string(char* input) { return grpc_json_parse_string_with_len(input, UNBOUND_JSON_STRING_LENGTH); } -static void json_dump_recursive(grpc_json_writer* writer, - grpc_json* json, int in_object) { +static void json_dump_recursive(grpc_json_writer* writer, grpc_json* json, + int in_object) { while (json) { if (in_object) grpc_json_writer_object_key(writer, json->key); @@ -370,10 +360,8 @@ static void json_dump_recursive(grpc_json_writer* writer, } static grpc_json_writer_vtable writer_vtable = { - json_writer_output_char, - json_writer_output_string, - json_writer_output_string_with_len -}; + json_writer_output_char, json_writer_output_string, + json_writer_output_string_with_len}; char* grpc_json_dump_to_string(grpc_json* json, int indent) { grpc_json_writer writer; diff --git a/src/core/json/json_writer.c b/src/core/json/json_writer.c index bed9a9bfa5..ca9c835825 100644 --- a/src/core/json/json_writer.c +++ b/src/core/json/json_writer.c @@ -41,11 +41,13 @@ static void json_writer_output_char(grpc_json_writer* writer, char c) { writer->vtable->output_char(writer->userdata, c); } -static void json_writer_output_string(grpc_json_writer* writer, const char* str) { +static void json_writer_output_string(grpc_json_writer* writer, + const char* str) { writer->vtable->output_string(writer->userdata, str); } -static void json_writer_output_string_with_len(grpc_json_writer* writer, const char* str, size_t len) { +static void json_writer_output_string_with_len(grpc_json_writer* writer, + const char* str, size_t len) { writer->vtable->output_string_with_len(writer->userdata, str, len); } @@ -58,8 +60,7 @@ void grpc_json_writer_init(grpc_json_writer* writer, int indent, writer->userdata = userdata; } -static void json_writer_output_indent( - grpc_json_writer* writer) { +static void json_writer_output_indent(grpc_json_writer* writer) { static const char spacesstr[] = " " " " @@ -99,14 +100,15 @@ static void json_writer_value_end(grpc_json_writer* writer) { } } -static void json_writer_escape_utf16(grpc_json_writer* writer, gpr_uint16 utf16) { +static void json_writer_escape_utf16(grpc_json_writer* writer, + gpr_uint16 utf16) { static const char hex[] = "0123456789abcdef"; json_writer_output_string_with_len(writer, "\\u", 2); json_writer_output_char(writer, hex[(utf16 >> 12) & 0x0f]); json_writer_output_char(writer, hex[(utf16 >> 8) & 0x0f]); json_writer_output_char(writer, hex[(utf16 >> 4) & 0x0f]); - json_writer_output_char(writer, hex[(utf16) & 0x0f]); + json_writer_output_char(writer, hex[(utf16)&0x0f]); } static void json_writer_escape_string(grpc_json_writer* writer, @@ -173,8 +175,8 @@ static void json_writer_escape_string(grpc_json_writer* writer, * Any other range is technically reserved for future usage, so if we * don't want the software to break in the future, we have to allow * anything else. The first non-unicode character is 0x110000. */ - if (((utf32 >= 0xd800) && (utf32 <= 0xdfff)) || - (utf32 >= 0x110000)) break; + if (((utf32 >= 0xd800) && (utf32 <= 0xdfff)) || (utf32 >= 0x110000)) + break; if (utf32 >= 0x10000) { /* If utf32 contains a character that is above 0xffff, it needs to be * broken down into a utf-16 surrogate pair. A surrogate pair is first @@ -194,7 +196,8 @@ static void json_writer_escape_string(grpc_json_writer* writer, */ utf32 -= 0x10000; json_writer_escape_utf16(writer, (gpr_uint16)(0xd800 | (utf32 >> 10))); - json_writer_escape_utf16(writer, (gpr_uint16)(0xdc00 | (utf32 & 0x3ff))); + json_writer_escape_utf16(writer, + (gpr_uint16)(0xdc00 | (utf32 & 0x3ff))); } else { json_writer_escape_utf16(writer, (gpr_uint16)utf32); } @@ -204,7 +207,8 @@ static void json_writer_escape_string(grpc_json_writer* writer, json_writer_output_char(writer, '"'); } -void grpc_json_writer_container_begins(grpc_json_writer* writer, grpc_json_type type) { +void grpc_json_writer_container_begins(grpc_json_writer* writer, + grpc_json_type type) { if (!writer->got_key) json_writer_value_end(writer); json_writer_output_indent(writer); json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '{' : '['); @@ -213,7 +217,8 @@ void grpc_json_writer_container_begins(grpc_json_writer* writer, grpc_json_type writer->depth++; } -void grpc_json_writer_container_ends(grpc_json_writer* writer, grpc_json_type type) { +void grpc_json_writer_container_ends(grpc_json_writer* writer, + grpc_json_type type) { if (writer->indent && !writer->container_empty) json_writer_output_char(writer, '\n'); writer->depth--; @@ -238,14 +243,16 @@ void grpc_json_writer_value_raw(grpc_json_writer* writer, const char* string) { writer->got_key = 0; } -void grpc_json_writer_value_raw_with_len(grpc_json_writer* writer, const char* string, size_t len) { +void grpc_json_writer_value_raw_with_len(grpc_json_writer* writer, + const char* string, size_t len) { if (!writer->got_key) json_writer_value_end(writer); json_writer_output_indent(writer); json_writer_output_string_with_len(writer, string, len); writer->got_key = 0; } -void grpc_json_writer_value_string(grpc_json_writer* writer, const char* string) { +void grpc_json_writer_value_string(grpc_json_writer* writer, + const char* string) { if (!writer->got_key) json_writer_value_end(writer); json_writer_output_indent(writer); json_writer_escape_string(writer, string); diff --git a/src/core/json/json_writer.h b/src/core/json/json_writer.h index dfa61a5fef..a299dfabf8 100644 --- a/src/core/json/json_writer.h +++ b/src/core/json/json_writer.h @@ -78,16 +78,20 @@ void grpc_json_writer_init(grpc_json_writer* writer, int indent, grpc_json_writer_vtable* vtable, void* userdata); /* Signals the beginning of a container. */ -void grpc_json_writer_container_begins(grpc_json_writer* writer, grpc_json_type type); +void grpc_json_writer_container_begins(grpc_json_writer* writer, + grpc_json_type type); /* Signals the end of a container. */ -void grpc_json_writer_container_ends(grpc_json_writer* writer, grpc_json_type type); +void grpc_json_writer_container_ends(grpc_json_writer* writer, + grpc_json_type type); /* Writes down an object key for the next value. */ void grpc_json_writer_object_key(grpc_json_writer* writer, const char* string); /* Sets a raw value. Useful for numbers. */ void grpc_json_writer_value_raw(grpc_json_writer* writer, const char* string); /* Sets a raw value with its length. Useful for values like true or false. */ -void grpc_json_writer_value_raw_with_len(grpc_json_writer* writer, const char* string, size_t len); +void grpc_json_writer_value_raw_with_len(grpc_json_writer* writer, + const char* string, size_t len); /* Sets a string value. It'll be escaped, and utf-8 validated. */ -void grpc_json_writer_value_string(grpc_json_writer* writer, const char* string); +void grpc_json_writer_value_string(grpc_json_writer* writer, + const char* string); -#endif /* GRPC_INTERNAL_CORE_JSON_JSON_WRITER_H */ +#endif /* GRPC_INTERNAL_CORE_JSON_JSON_WRITER_H */ diff --git a/src/core/profiling/timers.h b/src/core/profiling/timers.h index 036d02f187..92dbab9042 100644 --- a/src/core/profiling/timers.h +++ b/src/core/profiling/timers.h @@ -88,7 +88,7 @@ enum grpc_profiling_tags { } while (0) #define GRPC_TIMER_IMPORTANT_MARK(tag, id) \ - do { \ + do { \ } while (0) #define GRPC_TIMER_BEGIN(tag, id) \ diff --git a/src/core/security/auth_filters.h b/src/core/security/auth_filters.h index ff921690e0..c179b54bec 100644 --- a/src/core/security/auth_filters.h +++ b/src/core/security/auth_filters.h @@ -39,4 +39,4 @@ extern const grpc_channel_filter grpc_client_auth_filter; extern const grpc_channel_filter grpc_server_auth_filter; -#endif /* GRPC_INTERNAL_CORE_SECURITY_AUTH_FILTERS_H */ +#endif /* GRPC_INTERNAL_CORE_SECURITY_AUTH_FILTERS_H */ diff --git a/src/core/security/base64.h b/src/core/security/base64.h index b9abc07b52..31ae982691 100644 --- a/src/core/security/base64.h +++ b/src/core/security/base64.h @@ -49,4 +49,4 @@ gpr_slice grpc_base64_decode(const char *b64, int url_safe); gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len, int url_safe); -#endif /* GRPC_INTERNAL_CORE_SECURITY_BASE64_H */ +#endif /* GRPC_INTERNAL_CORE_SECURITY_BASE64_H */ diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c index 410852da52..8e63978b82 100644 --- a/src/core/security/client_auth_filter.c +++ b/src/core/security/client_auth_filter.c @@ -200,7 +200,7 @@ static void auth_start_transport_op(grpc_call_element *elem, channel_data *chand = elem->channel_data; grpc_linked_mdelem *l; size_t i; - grpc_client_security_context* sec_ctx = NULL; + grpc_client_security_context *sec_ctx = NULL; if (calld->security_context_set == 0) { calld->security_context_set = 1; @@ -316,9 +316,11 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, (grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF( sc, "client_auth_filter"); chand->md_ctx = metadata_context; - chand->authority_string = grpc_mdstr_from_string(chand->md_ctx, ":authority", 0); + chand->authority_string = + grpc_mdstr_from_string(chand->md_ctx, ":authority", 0); chand->path_string = grpc_mdstr_from_string(chand->md_ctx, ":path", 0); - chand->error_msg_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-message", 0); + chand->error_msg_key = + grpc_mdstr_from_string(chand->md_ctx, "grpc-message", 0); chand->status_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-status", 0); } diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index 6421ce673d..8852cab3e7 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -793,16 +793,16 @@ void on_simulated_token_fetch_done(void *user_data, int success) { (grpc_credentials_metadata_request *)user_data; grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds; GPR_ASSERT(success); - r->cb(r->user_data, c->md_store->entries, - c->md_store->num_entries, GRPC_CREDENTIALS_OK); + r->cb(r->user_data, c->md_store->entries, c->md_store->num_entries, + GRPC_CREDENTIALS_OK); grpc_credentials_metadata_request_destroy(r); } static void md_only_test_get_request_metadata(grpc_credentials *creds, - grpc_pollset *pollset, - const char *service_url, - grpc_credentials_metadata_cb cb, - void *user_data) { + grpc_pollset *pollset, + const char *service_url, + grpc_credentials_metadata_cb cb, + void *user_data) { grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; if (c->is_async) { @@ -854,10 +854,10 @@ static int access_token_has_request_metadata_only( } static void access_token_get_request_metadata(grpc_credentials *creds, - grpc_pollset *pollset, - const char *service_url, - grpc_credentials_metadata_cb cb, - void *user_data) { + grpc_pollset *pollset, + const char *service_url, + grpc_credentials_metadata_cb cb, + void *user_data) { grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds; cb(user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK); } diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h index 04736525dc..29cd1ac87f 100644 --- a/src/core/security/credentials.h +++ b/src/core/security/credentials.h @@ -192,8 +192,9 @@ void grpc_flush_cached_google_default_credentials(void); /* Metadata-only credentials with the specified key and value where asynchronicity can be simulated for testing. */ -grpc_credentials *grpc_md_only_test_credentials_create( - const char *md_key, const char *md_value, int is_async); +grpc_credentials *grpc_md_only_test_credentials_create(const char *md_key, + const char *md_value, + int is_async); /* Private constructor for jwt credentials from an already parsed json key. Takes ownership of the key. */ diff --git a/src/core/security/credentials_metadata.c b/src/core/security/credentials_metadata.c index 22c786be56..b8a132f1ea 100644 --- a/src/core/security/credentials_metadata.c +++ b/src/core/security/credentials_metadata.c @@ -47,7 +47,8 @@ static void store_ensure_capacity(grpc_credentials_md_store *store) { grpc_credentials_md_store *grpc_credentials_md_store_create( size_t initial_capacity) { - grpc_credentials_md_store *store = gpr_malloc(sizeof(grpc_credentials_md_store)); + grpc_credentials_md_store *store = + gpr_malloc(sizeof(grpc_credentials_md_store)); memset(store, 0, sizeof(grpc_credentials_md_store)); if (initial_capacity > 0) { store->entries = gpr_malloc(initial_capacity * sizeof(grpc_credentials_md)); @@ -98,4 +99,3 @@ void grpc_credentials_md_store_unref(grpc_credentials_md_store *store) { gpr_free(store); } } - diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c index d1f228665f..d6092ece32 100644 --- a/src/core/security/google_default_credentials.c +++ b/src/core/security/google_default_credentials.c @@ -203,8 +203,8 @@ end: /* Blend with default ssl credentials and add a global reference so that it can be cached and re-served. */ grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL); - default_credentials = grpc_credentials_ref(grpc_composite_credentials_create( - ssl_creds, result)); + default_credentials = grpc_credentials_ref( + grpc_composite_credentials_create(ssl_creds, result)); GPR_ASSERT(default_credentials != NULL); grpc_credentials_unref(ssl_creds); grpc_credentials_unref(result); diff --git a/src/core/security/json_token.h b/src/core/security/json_token.h index 091dfefb6e..7e06864ff3 100644 --- a/src/core/security/json_token.h +++ b/src/core/security/json_token.h @@ -115,4 +115,4 @@ grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json( /* Destructs the object. */ void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token); -#endif /* GRPC_INTERNAL_CORE_SECURITY_JSON_TOKEN_H */ +#endif /* GRPC_INTERNAL_CORE_SECURITY_JSON_TOKEN_H */ diff --git a/src/core/security/jwt_verifier.h b/src/core/security/jwt_verifier.h index 8077e24883..7a32debfcb 100644 --- a/src/core/security/jwt_verifier.h +++ b/src/core/security/jwt_verifier.h @@ -133,4 +133,3 @@ grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims, const char *audience); #endif /* GRPC_INTERNAL_CORE_SECURITY_JWT_VERIFIER_H */ - diff --git a/src/core/security/secure_endpoint.c b/src/core/security/secure_endpoint.c index 95fbf71f3d..81b3e33cb2 100644 --- a/src/core/security/secure_endpoint.c +++ b/src/core/security/secure_endpoint.c @@ -332,7 +332,7 @@ static void endpoint_add_to_pollset(grpc_endpoint *secure_ep, } static void endpoint_add_to_pollset_set(grpc_endpoint *secure_ep, - grpc_pollset_set *pollset_set) { + grpc_pollset_set *pollset_set) { secure_endpoint *ep = (secure_endpoint *)secure_ep; grpc_endpoint_add_to_pollset_set(ep->wrapped_ep, pollset_set); } diff --git a/src/core/security/secure_endpoint.h b/src/core/security/secure_endpoint.h index 93c29b5111..c563bdd9c5 100644 --- a/src/core/security/secure_endpoint.h +++ b/src/core/security/secure_endpoint.h @@ -46,4 +46,4 @@ grpc_endpoint *grpc_secure_endpoint_create( struct tsi_frame_protector *protector, grpc_endpoint *to_wrap, gpr_slice *leftover_slices, size_t leftover_nslices); -#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURE_ENDPOINT_H */ +#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURE_ENDPOINT_H */ diff --git a/src/core/security/secure_transport_setup.h b/src/core/security/secure_transport_setup.h index 29025f5236..d9b802556d 100644 --- a/src/core/security/secure_transport_setup.h +++ b/src/core/security/secure_transport_setup.h @@ -50,4 +50,4 @@ void grpc_setup_secure_transport(grpc_security_connector *connector, grpc_secure_transport_setup_done_cb cb, void *user_data); -#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURE_TRANSPORT_SETUP_H */ +#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURE_TRANSPORT_SETUP_H */ diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c index 1ef0fc9255..c1b434f302 100644 --- a/src/core/security/security_context.c +++ b/src/core/security/security_context.c @@ -204,8 +204,7 @@ int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context *ctx, return 1; } -int grpc_auth_context_peer_is_authenticated( - const grpc_auth_context *ctx) { +int grpc_auth_context_peer_is_authenticated(const grpc_auth_context *ctx) { return ctx->peer_identity_property_name == NULL ? 0 : 1; } @@ -326,4 +325,3 @@ grpc_auth_metadata_processor *grpc_find_auth_metadata_processor_in_args( } return NULL; } - diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h index 7fcd438cf6..a9a0306410 100644 --- a/src/core/security/security_context.h +++ b/src/core/security/security_context.h @@ -112,5 +112,4 @@ grpc_auth_metadata_processor *grpc_auth_metadata_processor_from_arg( grpc_auth_metadata_processor *grpc_find_auth_metadata_processor_in_args( const grpc_channel_args *args); -#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */ - +#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */ diff --git a/src/core/security/server_auth_filter.c b/src/core/security/server_auth_filter.c index 2fc689caec..2f42f01f53 100644 --- a/src/core/security/server_auth_filter.c +++ b/src/core/security/server_auth_filter.c @@ -212,8 +212,7 @@ static void init_call_elem(grpc_call_element *elem, } /* Destructor for call_data */ -static void destroy_call_elem(grpc_call_element *elem) { -} +static void destroy_call_elem(grpc_call_element *elem) {} /* Constructor for channel_data */ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, diff --git a/src/core/statistics/census_interface.h b/src/core/statistics/census_interface.h index eb4349c311..ac1ff24866 100644 --- a/src/core/statistics/census_interface.h +++ b/src/core/statistics/census_interface.h @@ -73,4 +73,4 @@ census_op_id census_tracing_start_op(void); /* Ends tracing. Calling this function will invalidate the input op_id. */ void census_tracing_end_op(census_op_id op_id); -#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_INTERFACE_H */ +#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_INTERFACE_H */ diff --git a/src/core/statistics/census_log.h b/src/core/statistics/census_log.h index 06869b7a33..60b6d597df 100644 --- a/src/core/statistics/census_log.h +++ b/src/core/statistics/census_log.h @@ -88,4 +88,4 @@ size_t census_log_remaining_space(void); out-of-space. */ int census_log_out_of_space_count(void); -#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_LOG_H */ +#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_LOG_H */ diff --git a/src/core/statistics/census_rpc_stats.c b/src/core/statistics/census_rpc_stats.c index 3e571b1143..b836987cf0 100644 --- a/src/core/statistics/census_rpc_stats.c +++ b/src/core/statistics/census_rpc_stats.c @@ -85,8 +85,8 @@ static void delete_key(void* key) { gpr_free(key); } static const census_ht_option ht_opt = { CENSUS_HT_POINTER /* key type */, 1999 /* n_of_buckets */, - simple_hash /* hash function */, cmp_str_keys /* key comparator */, - delete_stats /* data deleter */, delete_key /* key deleter */ + simple_hash /* hash function */, cmp_str_keys /* key comparator */, + delete_stats /* data deleter */, delete_key /* key deleter */ }; static void init_rpc_stats(void* stats) { diff --git a/src/core/statistics/census_rpc_stats.h b/src/core/statistics/census_rpc_stats.h index 9336dce1f8..aec31c1971 100644 --- a/src/core/statistics/census_rpc_stats.h +++ b/src/core/statistics/census_rpc_stats.h @@ -98,4 +98,4 @@ void census_stats_store_shutdown(void); } #endif -#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_RPC_STATS_H */ +#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_RPC_STATS_H */ diff --git a/src/core/statistics/census_tracing.c b/src/core/statistics/census_tracing.c index 3036ba5407..f2a09dc06e 100644 --- a/src/core/statistics/census_tracing.c +++ b/src/core/statistics/census_tracing.c @@ -60,8 +60,11 @@ static void delete_trace_obj(void* obj) { } static const census_ht_option ht_opt = { - CENSUS_HT_UINT64 /* key type*/, 571 /* n_of_buckets */, NULL /* hash */, - NULL /* compare_keys */, delete_trace_obj /* delete data */, + CENSUS_HT_UINT64 /* key type*/, + 571 /* n_of_buckets */, + NULL /* hash */, + NULL /* compare_keys */, + delete_trace_obj /* delete data */, NULL /* delete key */ }; diff --git a/src/core/statistics/census_tracing.h b/src/core/statistics/census_tracing.h index a4494b510c..08305c2469 100644 --- a/src/core/statistics/census_tracing.h +++ b/src/core/statistics/census_tracing.h @@ -93,4 +93,4 @@ census_trace_obj** census_get_active_ops(int* num_active_ops); } #endif -#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_TRACING_H */ +#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_TRACING_H */ diff --git a/src/core/statistics/hash_table.h b/src/core/statistics/hash_table.h index 7bcb4bcd9b..b7f8e11af4 100644 --- a/src/core/statistics/hash_table.h +++ b/src/core/statistics/hash_table.h @@ -128,4 +128,4 @@ typedef void (*census_ht_itr_cb)(census_ht_key key, const void* val_ptr, should not invalidate data entries. */ gpr_uint64 census_ht_for_all(const census_ht* ht, census_ht_itr_cb); -#endif /* GRPC_INTERNAL_CORE_STATISTICS_HASH_TABLE_H */ +#endif /* GRPC_INTERNAL_CORE_STATISTICS_HASH_TABLE_H */ diff --git a/src/core/support/cpu_iphone.c b/src/core/support/cpu_iphone.c index d412a6d7ee..82b49b47bc 100644 --- a/src/core/support/cpu_iphone.c +++ b/src/core/support/cpu_iphone.c @@ -36,9 +36,7 @@ #ifdef GPR_CPU_IPHONE /* Probably 2 instead of 1, but see comment on gpr_cpu_current_cpu. */ -unsigned gpr_cpu_num_cores(void) { - return 1; -} +unsigned gpr_cpu_num_cores(void) { return 1; } /* Most code that's using this is using it to shard across work queues. So unless profiling shows it's a problem or there appears a way to detect the @@ -46,8 +44,6 @@ unsigned gpr_cpu_num_cores(void) { Note that the interface in cpu.h lets gpr_cpu_num_cores return 0, but doing it makes it impossible for gpr_cpu_current_cpu to satisfy its stated range, and some code might be relying on it. */ -unsigned gpr_cpu_current_cpu(void) { - return 0; -} +unsigned gpr_cpu_current_cpu(void) { return 0; } #endif /* GPR_CPU_IPHONE */ diff --git a/src/core/support/cpu_linux.c b/src/core/support/cpu_linux.c index 282d4daab1..7af6a8f009 100644 --- a/src/core/support/cpu_linux.c +++ b/src/core/support/cpu_linux.c @@ -33,7 +33,7 @@ #ifndef _GNU_SOURCE #define _GNU_SOURCE -#endif /* _GNU_SOURCE */ +#endif /* _GNU_SOURCE */ #include <grpc/support/port_platform.h> diff --git a/src/core/support/env.h b/src/core/support/env.h index 4f2e394d14..24172d8673 100644 --- a/src/core/support/env.h +++ b/src/core/support/env.h @@ -57,4 +57,4 @@ void gpr_setenv(const char *name, const char *value); } #endif -#endif /* GRPC_INTERNAL_CORE_SUPPORT_ENV_H */ +#endif /* GRPC_INTERNAL_CORE_SUPPORT_ENV_H */ diff --git a/src/core/support/file.h b/src/core/support/file.h index 1dafe390e3..d8b7cea44f 100644 --- a/src/core/support/file.h +++ b/src/core/support/file.h @@ -60,4 +60,4 @@ FILE *gpr_tmpfile(const char *prefix, char **tmp_filename); } #endif -#endif /* GRPC_INTERNAL_CORE_SUPPORT_FILE_H */ +#endif /* GRPC_INTERNAL_CORE_SUPPORT_FILE_H */ diff --git a/src/core/support/histogram.c b/src/core/support/histogram.c index 9029703891..78dbf98684 100644 --- a/src/core/support/histogram.c +++ b/src/core/support/histogram.c @@ -191,15 +191,18 @@ static double threshold_for_count_below(gpr_histogram *h, double count_below) { break; } } - return (bucket_start(h, (double)lower_idx) + bucket_start(h, (double)upper_idx)) / 2.0; + return (bucket_start(h, (double)lower_idx) + + bucket_start(h, (double)upper_idx)) / + 2.0; } else { /* treat values as uniform throughout the bucket, and find where this value should lie */ lower_bound = bucket_start(h, (double)lower_idx); upper_bound = bucket_start(h, (double)(lower_idx + 1)); - return GPR_CLAMP(upper_bound - (upper_bound - lower_bound) * - (count_so_far - count_below) / - h->buckets[lower_idx], + return GPR_CLAMP(upper_bound - + (upper_bound - lower_bound) * + (count_so_far - count_below) / + h->buckets[lower_idx], h->min_seen, h->max_seen); } } diff --git a/src/core/support/log_linux.c b/src/core/support/log_linux.c index 5ac36e7b95..02f64d8b7e 100644 --- a/src/core/support/log_linux.c +++ b/src/core/support/log_linux.c @@ -93,8 +93,8 @@ void gpr_default_log(gpr_log_func_args *args) { } gpr_asprintf(&prefix, "%s%s.%09d %7tu %s:%d]", - gpr_log_severity_string(args->severity), time_buffer, - (int)(now.tv_nsec), gettid(), display_file, args->line); + gpr_log_severity_string(args->severity), time_buffer, + (int)(now.tv_nsec), gettid(), display_file, args->line); fprintf(stderr, "%-60s %s\n", prefix, args->message); gpr_free(prefix); diff --git a/src/core/support/murmur_hash.h b/src/core/support/murmur_hash.h index 85ab2fe4bf..343fcb99f7 100644 --- a/src/core/support/murmur_hash.h +++ b/src/core/support/murmur_hash.h @@ -41,4 +41,4 @@ /* compute the hash of key (length len) */ gpr_uint32 gpr_murmur_hash3(const void *key, size_t len, gpr_uint32 seed); -#endif /* GRPC_INTERNAL_CORE_SUPPORT_MURMUR_HASH_H */ +#endif /* GRPC_INTERNAL_CORE_SUPPORT_MURMUR_HASH_H */ diff --git a/src/core/support/slice.c b/src/core/support/slice.c index e4196a48c6..53024e88f1 100644 --- a/src/core/support/slice.c +++ b/src/core/support/slice.c @@ -284,7 +284,8 @@ gpr_slice gpr_slice_split_head(gpr_slice *source, size_t split) { head.refcount = NULL; head.data.inlined.length = (gpr_uint8)split; memcpy(head.data.inlined.bytes, source->data.inlined.bytes, split); - source->data.inlined.length = (gpr_uint8)(source->data.inlined.length - split); + source->data.inlined.length = + (gpr_uint8)(source->data.inlined.length - split); memmove(source->data.inlined.bytes, source->data.inlined.bytes + split, source->data.inlined.length); } else if (split < sizeof(head.data.inlined.bytes)) { diff --git a/src/core/support/slice_buffer.c b/src/core/support/slice_buffer.c index 6e6c72a2bf..987d5cb9b5 100644 --- a/src/core/support/slice_buffer.c +++ b/src/core/support/slice_buffer.c @@ -116,7 +116,8 @@ void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice s) { GPR_SLICE_INLINED_SIZE) { memcpy(back->data.inlined.bytes + back->data.inlined.length, s.data.inlined.bytes, s.data.inlined.length); - back->data.inlined.length = (gpr_uint8)(back->data.inlined.length + s.data.inlined.length); + back->data.inlined.length = + (gpr_uint8)(back->data.inlined.length + s.data.inlined.length); } else { size_t cp1 = GPR_SLICE_INLINED_SIZE - back->data.inlined.length; memcpy(back->data.inlined.bytes + back->data.inlined.length, diff --git a/src/core/support/stack_lockfree.c b/src/core/support/stack_lockfree.c index bc741f8c70..27ecf62280 100644 --- a/src/core/support/stack_lockfree.c +++ b/src/core/support/stack_lockfree.c @@ -67,7 +67,7 @@ typedef union lockfree_node { #define ENTRY_ALIGNMENT_BITS 3 /* make sure that entries aligned to 8-bytes */ #define INVALID_ENTRY_INDEX \ ((1 << 16) - 1) /* reserve this entry as invalid \ - */ + */ struct gpr_stack_lockfree { lockfree_node *entries; @@ -75,7 +75,7 @@ struct gpr_stack_lockfree { #ifndef NDEBUG /* Bitmap of pushed entries to check for double-push or pop */ - gpr_atm pushed[(INVALID_ENTRY_INDEX+1)/(8*sizeof(gpr_atm))]; + gpr_atm pushed[(INVALID_ENTRY_INDEX + 1) / (8 * sizeof(gpr_atm))]; #endif }; @@ -123,13 +123,13 @@ int gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) { #ifndef NDEBUG /* Check for double push */ { - int pushed_index = entry / (8*sizeof(gpr_atm)); - int pushed_bit = entry % (8*sizeof(gpr_atm)); + int pushed_index = entry / (8 * sizeof(gpr_atm)); + int pushed_bit = entry % (8 * sizeof(gpr_atm)); gpr_atm old_val; old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index], - (gpr_atm)(1UL << pushed_bit)); - GPR_ASSERT((old_val & (1UL<<pushed_bit)) == 0); + (gpr_atm)(1UL << pushed_bit)); + GPR_ASSERT((old_val & (1UL << pushed_bit)) == 0); } #endif @@ -161,13 +161,13 @@ int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) { #ifndef NDEBUG /* Check for valid pop */ { - int pushed_index = head.contents.index / (8*sizeof(gpr_atm)); - int pushed_bit = head.contents.index % (8*sizeof(gpr_atm)); + int pushed_index = head.contents.index / (8 * sizeof(gpr_atm)); + int pushed_bit = head.contents.index % (8 * sizeof(gpr_atm)); gpr_atm old_val; old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index], - -(gpr_atm)(1UL << pushed_bit)); - GPR_ASSERT((old_val & (1UL<<pushed_bit)) != 0); + -(gpr_atm)(1UL << pushed_bit)); + GPR_ASSERT((old_val & (1UL << pushed_bit)) != 0); } #endif diff --git a/src/core/support/string.c b/src/core/support/string.c index 9babbd910a..af0389ea83 100644 --- a/src/core/support/string.c +++ b/src/core/support/string.c @@ -125,7 +125,6 @@ char *gpr_dump_slice(gpr_slice s, gpr_uint32 flags) { flags); } - int gpr_parse_bytes_to_uint32(const char *buf, size_t len, gpr_uint32 *result) { gpr_uint32 out = 0; gpr_uint32 new; @@ -187,9 +186,9 @@ char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep, for (i = 0; i < nstrs; i++) { out_length += strlen(strs[i]); } - out_length += 1; /* null terminator */ + out_length += 1; /* null terminator */ if (nstrs > 0) { - out_length += sep_len * (nstrs - 1); /* separators */ + out_length += sep_len * (nstrs - 1); /* separators */ } out = gpr_malloc(out_length); out_length = 0; @@ -214,10 +213,8 @@ char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep, * str. * * Returns 1 and updates \a begin and \a end. Returns 0 otherwise. */ -static int slice_find_separator_offset(const gpr_slice str, - const char *sep, - const size_t read_offset, - size_t *begin, +static int slice_find_separator_offset(const gpr_slice str, const char *sep, + const size_t read_offset, size_t *begin, size_t *end) { size_t i; const gpr_uint8 *str_ptr = GPR_SLICE_START_PTR(str) + read_offset; @@ -255,9 +252,7 @@ void gpr_slice_split(gpr_slice str, const char *sep, gpr_slice_buffer *dst) { } } -void gpr_strvec_init(gpr_strvec *sv) { - memset(sv, 0, sizeof(*sv)); -} +void gpr_strvec_init(gpr_strvec *sv) { memset(sv, 0, sizeof(*sv)); } void gpr_strvec_destroy(gpr_strvec *sv) { size_t i; @@ -270,11 +265,11 @@ 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 * 2); - sv->strs = gpr_realloc(sv->strs, sizeof(char*) * sv->capacity); + sv->strs = gpr_realloc(sv->strs, sizeof(char *) * sv->capacity); } sv->strs[sv->count++] = str; } char *gpr_strvec_flatten(gpr_strvec *sv, size_t *final_length) { - return gpr_strjoin((const char**)sv->strs, sv->count, 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 3ac4abeef8..a28e00fd3e 100644 --- a/src/core/support/string.h +++ b/src/core/support/string.h @@ -47,7 +47,7 @@ extern "C" { /* String utility functions */ /* Flags for gpr_dump function. */ -#define GPR_DUMP_HEX 0x00000001 +#define GPR_DUMP_HEX 0x00000001 #define GPR_DUMP_ASCII 0x00000002 /* Converts array buf, of length len, into a C string according to the flags. @@ -108,4 +108,4 @@ char *gpr_strvec_flatten(gpr_strvec *strs, size_t *total_length); } #endif -#endif /* GRPC_INTERNAL_CORE_SUPPORT_STRING_H */ +#endif /* GRPC_INTERNAL_CORE_SUPPORT_STRING_H */ diff --git a/src/core/support/string_win32.c b/src/core/support/string_win32.c index 27b9f3637a..8ffb0a225e 100644 --- a/src/core/support/string_win32.c +++ b/src/core/support/string_win32.c @@ -99,13 +99,9 @@ LPSTR gpr_tchar_to_char(LPCTSTR input) { return ret; } #else -char *gpr_tchar_to_char(LPTSTR input) { - return gpr_strdup(input); -} +char *gpr_tchar_to_char(LPTSTR input) { return gpr_strdup(input); } -char *gpr_char_to_tchar(LPTSTR input) { - return gpr_strdup(input); -} +char *gpr_char_to_tchar(LPTSTR input) { return gpr_strdup(input); } #endif #endif /* GPR_WIN32 */ diff --git a/src/core/support/string_win32.h b/src/core/support/string_win32.h index 1260aa55c1..e3043656fb 100644 --- a/src/core/support/string_win32.h +++ b/src/core/support/string_win32.h @@ -42,6 +42,6 @@ LPTSTR gpr_char_to_tchar(LPCSTR input); LPSTR gpr_tchar_to_char(LPCTSTR input); -#endif /* GPR_WIN32 */ +#endif /* GPR_WIN32 */ -#endif /* GRPC_INTERNAL_CORE_SUPPORT_STRING_WIN32_H */ +#endif /* GRPC_INTERNAL_CORE_SUPPORT_STRING_WIN32_H */ diff --git a/src/core/support/sync_posix.c b/src/core/support/sync_posix.c index 61572b9a8e..6f078cd4bb 100644 --- a/src/core/support/sync_posix.c +++ b/src/core/support/sync_posix.c @@ -63,7 +63,8 @@ void gpr_cv_destroy(gpr_cv *cv) { GPR_ASSERT(pthread_cond_destroy(cv) == 0); } int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) { int err = 0; - if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) == 0) { + if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) == + 0) { err = pthread_cond_wait(cv, mu); } else { struct timespec abs_deadline_ts; diff --git a/src/core/support/sync_win32.c b/src/core/support/sync_win32.c index 54f84a46ac..df23492171 100644 --- a/src/core/support/sync_win32.c +++ b/src/core/support/sync_win32.c @@ -83,7 +83,8 @@ int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) { int timeout = 0; DWORD timeout_max_ms; mu->locked = 0; - if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) == 0) { + if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) == + 0) { SleepConditionVariableCS(cv, &mu->cs, INFINITE); } else { gpr_timespec now = gpr_now(abs_deadline.clock_type); diff --git a/src/core/support/thd.c b/src/core/support/thd.c index ec308f3119..32c0db5b66 100644 --- a/src/core/support/thd.c +++ b/src/core/support/thd.c @@ -37,9 +37,7 @@ #include <grpc/support/thd.h> -enum { - GPR_THD_JOINABLE = 1 -}; +enum { GPR_THD_JOINABLE = 1 }; gpr_thd_options gpr_thd_options_default(void) { gpr_thd_options options; diff --git a/src/core/support/thd_internal.h b/src/core/support/thd_internal.h index 4683c37742..1508c4691f 100644 --- a/src/core/support/thd_internal.h +++ b/src/core/support/thd_internal.h @@ -36,4 +36,4 @@ /* Internal interfaces between modules within the gpr support library. */ -#endif /* GRPC_INTERNAL_CORE_SUPPORT_THD_INTERNAL_H */ +#endif /* GRPC_INTERNAL_CORE_SUPPORT_THD_INTERNAL_H */ diff --git a/src/core/support/thd_posix.c b/src/core/support/thd_posix.c index fa4eb50556..c36d94d044 100644 --- a/src/core/support/thd_posix.c +++ b/src/core/support/thd_posix.c @@ -69,9 +69,11 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, GPR_ASSERT(pthread_attr_init(&attr) == 0); if (gpr_thd_options_is_detached(options)) { - GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0); + GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == + 0); } else { - GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == 0); + GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == + 0); } thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0); GPR_ASSERT(pthread_attr_destroy(&attr) == 0); @@ -82,12 +84,8 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, return thread_started; } -gpr_thd_id gpr_thd_currentid(void) { - return (gpr_thd_id)pthread_self(); -} +gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); } -void gpr_thd_join(gpr_thd_id t) { - pthread_join((pthread_t)t, NULL); -} +void gpr_thd_join(gpr_thd_id t) { pthread_join((pthread_t)t, NULL); } #endif /* GPR_POSIX_SYNC */ diff --git a/src/core/support/thd_win32.c b/src/core/support/thd_win32.c index 4fa3907444..a9db180c1b 100644 --- a/src/core/support/thd_win32.c +++ b/src/core/support/thd_win32.c @@ -105,9 +105,7 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, return handle != NULL; } -gpr_thd_id gpr_thd_currentid(void) { - return (gpr_thd_id)g_thd_info; -} +gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; } void gpr_thd_join(gpr_thd_id t) { struct thd_info *info = (struct thd_info *)t; diff --git a/src/core/support/time.c b/src/core/support/time.c index b523ae01cc..929adac918 100644 --- a/src/core/support/time.c +++ b/src/core/support/time.c @@ -315,5 +315,6 @@ gpr_timespec gpr_convert_clock_type(gpr_timespec t, gpr_clock_type clock_type) { return gpr_time_add(gpr_now(clock_type), t); } - return gpr_time_add(gpr_now(clock_type), gpr_time_sub(t, gpr_now(t.clock_type))); + return gpr_time_add(gpr_now(clock_type), + gpr_time_sub(t, gpr_now(t.clock_type))); } diff --git a/src/core/support/tls_pthread.c b/src/core/support/tls_pthread.c index f2e76a553f..2d28226fc4 100644 --- a/src/core/support/tls_pthread.c +++ b/src/core/support/tls_pthread.c @@ -38,7 +38,7 @@ #include <grpc/support/tls.h> gpr_intptr gpr_tls_set(struct gpr_pthread_thread_local *tls, gpr_intptr value) { - GPR_ASSERT(0 == pthread_setspecific(tls->key, (void*)value)); + GPR_ASSERT(0 == pthread_setspecific(tls->key, (void *)value)); return value; } diff --git a/src/core/surface/byte_buffer_queue.h b/src/core/surface/byte_buffer_queue.h index f01958984f..2c3b22d24e 100644 --- a/src/core/surface/byte_buffer_queue.h +++ b/src/core/surface/byte_buffer_queue.h @@ -59,4 +59,4 @@ int grpc_bbq_empty(grpc_byte_buffer_queue *q); void grpc_bbq_push(grpc_byte_buffer_queue *q, grpc_byte_buffer *bb); size_t grpc_bbq_bytes(grpc_byte_buffer_queue *q); -#endif /* GRPC_INTERNAL_CORE_SURFACE_BYTE_BUFFER_QUEUE_H */ +#endif /* GRPC_INTERNAL_CORE_SURFACE_BYTE_BUFFER_QUEUE_H */ diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 6a1a6cbf30..33f277da46 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -39,6 +39,7 @@ #include <grpc/support/alloc.h> #include <grpc/support/log.h> #include <grpc/support/string_util.h> +#include <grpc/support/useful.h> #include "src/core/channel/channel_stack.h" #include "src/core/iomgr/alarm.h" @@ -242,6 +243,9 @@ struct grpc_call { /* Compression algorithm for the call */ grpc_compression_algorithm compression_algorithm; + /* Supported encodings (compression algorithms), a bitset */ + gpr_uint32 encodings_accepted_by_peer; + /* Contexts for various subsystems (security, tracing, ...). */ grpc_call_context_element context[GRPC_CONTEXT_COUNT]; @@ -272,7 +276,8 @@ struct grpc_call { /** completion events - for completion queue use */ grpc_cq_completion completions[MAX_CONCURRENT_COMPLETIONS]; - /** siblings: children of the same parent form a list, and this list is protected under + /** siblings: children of the same parent form a list, and this list is + protected under parent->mu */ grpc_call *sibling_next; grpc_call *sibling_prev; @@ -394,7 +399,8 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call, } else { call->sibling_next = parent_call->first_child; call->sibling_prev = parent_call->first_child->sibling_prev; - call->sibling_next->sibling_prev = call->sibling_prev->sibling_next = call; + call->sibling_next->sibling_prev = call->sibling_prev->sibling_next = + call; } gpr_mu_unlock(&parent_call->mu); @@ -532,6 +538,45 @@ grpc_compression_algorithm grpc_call_get_compression_algorithm( return call->compression_algorithm; } +static void set_encodings_accepted_by_peer( + grpc_call *call, const gpr_slice accept_encoding_slice) { + size_t i; + grpc_compression_algorithm algorithm; + gpr_slice_buffer accept_encoding_parts; + + gpr_slice_buffer_init(&accept_encoding_parts); + gpr_slice_split(accept_encoding_slice, ", ", &accept_encoding_parts); + + /* No need to zero call->encodings_accepted_by_peer: grpc_call_create already + * zeroes the whole grpc_call */ + /* Always support no compression */ + GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE); + for (i = 0; i < accept_encoding_parts.count; i++) { + const gpr_slice *accept_encoding_entry_slice = + &accept_encoding_parts.slices[i]; + if (grpc_compression_algorithm_parse( + (const char *)GPR_SLICE_START_PTR(*accept_encoding_entry_slice), + GPR_SLICE_LENGTH(*accept_encoding_entry_slice), &algorithm)) { + GPR_BITSET(&call->encodings_accepted_by_peer, algorithm); + } else { + char *accept_encoding_entry_str = + gpr_dump_slice(*accept_encoding_entry_slice, GPR_DUMP_ASCII); + gpr_log(GPR_ERROR, + "Invalid entry in accept encoding metadata: '%s'. Ignoring.", + accept_encoding_entry_str); + gpr_free(accept_encoding_entry_str); + } + } +} + +gpr_uint32 grpc_call_get_encodings_accepted_by_peer(grpc_call *call) { + return call->encodings_accepted_by_peer; +} + +gpr_uint32 grpc_call_get_message_flags(const grpc_call *call) { + return call->incoming_message_flags; +} + static void set_status_details(grpc_call *call, status_source source, grpc_mdstr *status) { if (call->status[source].details != NULL) { @@ -1280,7 +1325,7 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call *c, const char *description, void *reserved) { grpc_call_error r; - (void) reserved; + (void)reserved; lock(c); r = cancel_with_status(c, status, description); unlock(c); @@ -1408,10 +1453,11 @@ static gpr_uint32 decode_compression(grpc_mdelem *md) { void *user_data = grpc_mdelem_get_user_data(md, destroy_compression); if (user_data) { algorithm = - ((grpc_compression_level)(gpr_intptr)user_data) - COMPRESS_OFFSET; + ((grpc_compression_algorithm)(gpr_intptr)user_data) - COMPRESS_OFFSET; } else { const char *md_c_str = grpc_mdstr_as_c_string(md->value); - if (!grpc_compression_algorithm_parse(md_c_str, &algorithm)) { + if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str), + &algorithm)) { gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'", md_c_str); assert(0); } @@ -1440,6 +1486,9 @@ static void recv_metadata(grpc_call *call, grpc_metadata_batch *md) { } else if (key == grpc_channel_get_compression_algorithm_string(call->channel)) { set_compression_algorithm(call, decode_compression(md)); + } else if (key == grpc_channel_get_encodings_accepted_by_peer_string( + call->channel)) { + set_encodings_accepted_by_peer(call, md->value->slice); } else { dest = &call->buffered_metadata[is_trailing]; if (dest->count == dest->capacity) { @@ -1524,7 +1573,8 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, const grpc_op *op; grpc_ioreq *req; void (*finish_func)(grpc_call *, int, void *) = finish_batch; - GPR_ASSERT(!reserved); + + if (reserved != NULL) return GRPC_CALL_ERROR; GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, tag); @@ -1539,12 +1589,13 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, /* rewrite batch ops into ioreq ops */ for (in = 0, out = 0; in < nops; in++) { op = &ops[in]; + if (op->reserved != NULL) return GRPC_CALL_ERROR; switch (op->op) { case GRPC_OP_SEND_INITIAL_METADATA: /* Flag validation: currently allow no flags */ if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; req = &reqs[out++]; - if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_INITIAL_METADATA; req->data.send_metadata.count = op->data.send_initial_metadata.count; req->data.send_metadata.metadata = @@ -1559,7 +1610,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, return GRPC_CALL_ERROR_INVALID_MESSAGE; } req = &reqs[out++]; - if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_MESSAGE; req->data.send_message = op->data.send_message; req->flags = op->flags; @@ -1571,7 +1622,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, return GRPC_CALL_ERROR_NOT_ON_SERVER; } req = &reqs[out++]; - if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_CLOSE; req->flags = op->flags; break; @@ -1582,7 +1633,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, return GRPC_CALL_ERROR_NOT_ON_CLIENT; } req = &reqs[out++]; - if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_TRAILING_METADATA; req->flags = op->flags; req->data.send_metadata.count = @@ -1590,7 +1641,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, req->data.send_metadata.metadata = op->data.send_status_from_server.trailing_metadata; req = &reqs[out++]; - if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_STATUS; req->data.send_status.code = op->data.send_status_from_server.status; req->data.send_status.details = @@ -1600,7 +1651,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, op->data.send_status_from_server.status_details, 0) : NULL; req = &reqs[out++]; - if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_SEND_CLOSE; break; case GRPC_OP_RECV_INITIAL_METADATA: @@ -1610,7 +1661,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, return GRPC_CALL_ERROR_NOT_ON_SERVER; } req = &reqs[out++]; - if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_INITIAL_METADATA; req->data.recv_metadata = op->data.recv_initial_metadata; req->data.recv_metadata->count = 0; @@ -1620,7 +1671,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, /* Flag validation: currently allow no flags */ if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; req = &reqs[out++]; - if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_MESSAGE; req->data.recv_message = op->data.recv_message; req->flags = op->flags; @@ -1632,26 +1683,26 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, return GRPC_CALL_ERROR_NOT_ON_SERVER; } req = &reqs[out++]; - if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_STATUS; req->flags = op->flags; req->data.recv_status.set_value = set_status_value_directly; req->data.recv_status.user_data = op->data.recv_status_on_client.status; req = &reqs[out++]; - if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_STATUS_DETAILS; req->data.recv_status_details.details = op->data.recv_status_on_client.status_details; req->data.recv_status_details.details_capacity = op->data.recv_status_on_client.status_details_capacity; req = &reqs[out++]; - if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_TRAILING_METADATA; req->data.recv_metadata = op->data.recv_status_on_client.trailing_metadata; req->data.recv_metadata->count = 0; req = &reqs[out++]; - if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_CLOSE; finish_func = finish_batch_with_close; break; @@ -1659,14 +1710,14 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, /* Flag validation: currently allow no flags */ if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; req = &reqs[out++]; - if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_STATUS; req->flags = op->flags; req->data.recv_status.set_value = set_cancelled_value; req->data.recv_status.user_data = op->data.recv_close_on_server.cancelled; req = &reqs[out++]; - if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; + if (out > GRPC_IOREQ_OP_COUNT) return GRPC_CALL_ERROR_BATCH_TOO_BIG; req->op = GRPC_IOREQ_RECV_CLOSE; finish_func = finish_batch_with_close; break; diff --git a/src/core/surface/call.h b/src/core/surface/call.h index 75bdbce980..00638e43b5 100644 --- a/src/core/surface/call.h +++ b/src/core/surface/call.h @@ -38,6 +38,10 @@ #include "src/core/channel/context.h" #include <grpc/grpc.h> +#ifdef __cplusplus +extern "C" { +#endif + /* Primitive operation types - grpc_op's get rewritten into these */ typedef enum { GRPC_IOREQ_RECV_INITIAL_METADATA, @@ -162,4 +166,19 @@ void *grpc_call_context_get(grpc_call *call, grpc_context_index elem); gpr_uint8 grpc_call_is_client(grpc_call *call); +grpc_compression_algorithm grpc_call_get_compression_algorithm( + const grpc_call *call); + +gpr_uint32 grpc_call_get_message_flags(const grpc_call *call); + +/** Returns a bitset for the encodings (compression algorithms) supported by \a + * call's peer. + * + * To be indexed by grpc_compression_algorithm enum values. */ +gpr_uint32 grpc_call_get_encodings_accepted_by_peer(grpc_call *call); + +#ifdef __cplusplus +} +#endif + #endif /* GRPC_INTERNAL_CORE_SURFACE_CALL_H */ diff --git a/src/core/surface/call_log_batch.c b/src/core/surface/call_log_batch.c index 7bf8cafc24..5a3ef1e5f4 100644 --- a/src/core/surface/call_log_batch.c +++ b/src/core/surface/call_log_batch.c @@ -41,7 +41,7 @@ int grpc_trace_batch = 0; static void add_metadata(gpr_strvec *b, const grpc_metadata *md, size_t count) { size_t i; - for(i = 0; i < count; i++) { + for (i = 0; i < count; i++) { gpr_strvec_add(b, gpr_strdup("\nkey=")); gpr_strvec_add(b, gpr_strdup(md[i].key)); @@ -113,8 +113,9 @@ void grpc_call_log_batch(char *file, int line, gpr_log_severity severity, char *tmp; size_t i; gpr_log(file, line, severity, - "grpc_call_start_batch(call=%p, ops=%p, nops=%d, tag=%p)", call, ops, nops, tag); - for(i = 0; i < nops; i++) { + "grpc_call_start_batch(call=%p, ops=%p, nops=%d, tag=%p)", call, ops, + nops, tag); + for (i = 0; i < nops; i++) { tmp = grpc_op_string(&ops[i]); gpr_log(file, line, severity, "ops[%d]: %s", i, tmp); gpr_free(tmp); @@ -123,8 +124,7 @@ void grpc_call_log_batch(char *file, int line, gpr_log_severity severity, void grpc_server_log_request_call(char *file, int line, gpr_log_severity severity, - grpc_server *server, - grpc_call **call, + grpc_server *server, grpc_call **call, grpc_call_details *details, grpc_metadata_array *initial_metadata, grpc_completion_queue *cq_bound_to_call, @@ -133,8 +133,9 @@ void grpc_server_log_request_call(char *file, int line, gpr_log(file, line, severity, "grpc_server_request_call(server=%p, call=%p, details=%p, " "initial_metadata=%p, cq_bound_to_call=%p, cq_for_notification=%p, " - "tag=%p)", server, call, details, initial_metadata, - cq_bound_to_call, cq_for_notification, tag); + "tag=%p)", + server, call, details, initial_metadata, cq_bound_to_call, + cq_for_notification, tag); } void grpc_server_log_shutdown(char *file, int line, gpr_log_severity severity, diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c index 308572c634..e50251566d 100644 --- a/src/core/surface/channel.c +++ b/src/core/surface/channel.c @@ -66,6 +66,7 @@ struct grpc_channel { /** mdstr for the grpc-status key */ grpc_mdstr *grpc_status_string; grpc_mdstr *grpc_compression_algorithm_string; + grpc_mdstr *grpc_encodings_accepted_by_peer_string; grpc_mdstr *grpc_message_string; grpc_mdstr *path_string; grpc_mdstr *authority_string; @@ -104,7 +105,10 @@ grpc_channel *grpc_channel_create_from_filters( channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status", 0); channel->grpc_compression_algorithm_string = grpc_mdstr_from_string(mdctx, "grpc-encoding", 0); - channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message", 0); + channel->grpc_encodings_accepted_by_peer_string = + grpc_mdstr_from_string(mdctx, "grpc-accept-encoding", 0); + channel->grpc_message_string = + grpc_mdstr_from_string(mdctx, "grpc-message", 0); for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) { char buf[GPR_LTOA_MIN_BUFSIZE]; gpr_ltoa(i, buf); @@ -159,7 +163,7 @@ static grpc_call *grpc_channel_create_call_internal( send_metadata[num_metadata++] = authority_mdelem; } - return grpc_call_create(channel, parent_call, propagation_mask, cq, NULL, + return grpc_call_create(channel, parent_call, propagation_mask, cq, NULL, send_metadata, num_metadata, deadline); } @@ -175,10 +179,11 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel, grpc_mdelem_from_metadata_strings( channel->metadata_context, GRPC_MDSTR_REF(channel->path_string), grpc_mdstr_from_string(channel->metadata_context, method, 0)), - host ? - grpc_mdelem_from_metadata_strings( - channel->metadata_context, GRPC_MDSTR_REF(channel->authority_string), - grpc_mdstr_from_string(channel->metadata_context, host, 0)) : NULL, + host ? grpc_mdelem_from_metadata_strings( + channel->metadata_context, + GRPC_MDSTR_REF(channel->authority_string), + grpc_mdstr_from_string(channel->metadata_context, host, 0)) + : NULL, deadline); } @@ -189,9 +194,12 @@ void *grpc_channel_register_call(grpc_channel *channel, const char *method, rc->path = grpc_mdelem_from_metadata_strings( channel->metadata_context, GRPC_MDSTR_REF(channel->path_string), grpc_mdstr_from_string(channel->metadata_context, method, 0)); - rc->authority = host ? grpc_mdelem_from_metadata_strings( - channel->metadata_context, GRPC_MDSTR_REF(channel->authority_string), - grpc_mdstr_from_string(channel->metadata_context, host, 0)) : NULL; + rc->authority = + host ? grpc_mdelem_from_metadata_strings( + channel->metadata_context, + GRPC_MDSTR_REF(channel->authority_string), + grpc_mdstr_from_string(channel->metadata_context, host, 0)) + : NULL; gpr_mu_lock(&channel->registered_call_mu); rc->next = channel->registered_calls; channel->registered_calls = rc; @@ -206,8 +214,8 @@ grpc_call *grpc_channel_create_registered_call( registered_call *rc = registered_call_handle; GPR_ASSERT(!reserved); return grpc_channel_create_call_internal( - channel, parent_call, propagation_mask, completion_queue, - GRPC_MDELEM_REF(rc->path), + channel, parent_call, propagation_mask, completion_queue, + GRPC_MDELEM_REF(rc->path), rc->authority ? GRPC_MDELEM_REF(rc->authority) : NULL, deadline); } @@ -230,6 +238,7 @@ static void destroy_channel(void *p, int ok) { } GRPC_MDSTR_UNREF(channel->grpc_status_string); GRPC_MDSTR_UNREF(channel->grpc_compression_algorithm_string); + GRPC_MDSTR_UNREF(channel->grpc_encodings_accepted_by_peer_string); GRPC_MDSTR_UNREF(channel->grpc_message_string); GRPC_MDSTR_UNREF(channel->path_string); GRPC_MDSTR_UNREF(channel->authority_string); @@ -290,6 +299,11 @@ grpc_mdstr *grpc_channel_get_compression_algorithm_string( return channel->grpc_compression_algorithm_string; } +grpc_mdstr *grpc_channel_get_encodings_accepted_by_peer_string( + grpc_channel *channel) { + return channel->grpc_encodings_accepted_by_peer_string; +} + grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) { if (i >= 0 && i < NUM_CACHED_STATUS_ELEMS) { return GRPC_MDELEM_REF(channel->grpc_status_elem[i]); diff --git a/src/core/surface/channel.h b/src/core/surface/channel.h index 9e0646efaa..f271616f60 100644 --- a/src/core/surface/channel.h +++ b/src/core/surface/channel.h @@ -56,6 +56,8 @@ grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel); grpc_mdstr *grpc_channel_get_compression_algorithm_string( grpc_channel *channel); +grpc_mdstr *grpc_channel_get_encodings_accepted_by_peer_string( + grpc_channel *channel); grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel); gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel); diff --git a/src/core/surface/channel_connectivity.c b/src/core/surface/channel_connectivity.c index 1223706457..88a7c16598 100644 --- a/src/core/surface/channel_connectivity.c +++ b/src/core/surface/channel_connectivity.c @@ -77,9 +77,10 @@ typedef struct { } state_watcher; static void delete_state_watcher(state_watcher *w) { - grpc_channel_element *client_channel_elem = - grpc_channel_stack_last_element(grpc_channel_get_channel_stack(w->channel)); - grpc_client_channel_del_interested_party(client_channel_elem, grpc_cq_pollset(w->cq)); + grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element( + grpc_channel_get_channel_stack(w->channel)); + grpc_client_channel_del_interested_party(client_channel_elem, + grpc_cq_pollset(w->cq)); GRPC_CHANNEL_INTERNAL_UNREF(w->channel, "watch_connectivity"); gpr_mu_destroy(&w->mu); gpr_free(w); @@ -166,9 +167,9 @@ void grpc_channel_watch_connectivity_state( w->tag = tag; w->channel = channel; - grpc_alarm_init( - &w->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - timeout_complete, w, gpr_now(GPR_CLOCK_MONOTONIC)); + grpc_alarm_init(&w->alarm, + gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), + timeout_complete, w, gpr_now(GPR_CLOCK_MONOTONIC)); if (client_channel_elem->filter != &grpc_client_channel_filter) { gpr_log(GPR_ERROR, @@ -178,7 +179,8 @@ void grpc_channel_watch_connectivity_state( grpc_iomgr_add_delayed_callback(&w->on_complete, 1); } else { GRPC_CHANNEL_INTERNAL_REF(channel, "watch_connectivity"); - grpc_client_channel_add_interested_party(client_channel_elem, grpc_cq_pollset(cq)); + grpc_client_channel_add_interested_party(client_channel_elem, + grpc_cq_pollset(cq)); grpc_client_channel_watch_connectivity_state(client_channel_elem, &w->state, &w->on_complete); } diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c index 378b3f71a1..77443a7ae8 100644 --- a/src/core/surface/completion_queue.c +++ b/src/core/surface/completion_queue.c @@ -167,8 +167,7 @@ void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, int success, } grpc_event grpc_completion_queue_next(grpc_completion_queue *cc, - gpr_timespec deadline, - void *reserved) { + gpr_timespec deadline, void *reserved) { grpc_event ret; grpc_pollset_worker worker; GPR_ASSERT(!reserved); @@ -272,8 +271,9 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag, break; } if (!add_plucker(cc, tag, &worker)) { - gpr_log(GPR_DEBUG, - "Too many outstanding grpc_completion_queue_pluck calls: maximum is %d", + gpr_log(GPR_DEBUG, + "Too many outstanding grpc_completion_queue_pluck calls: maximum " + "is %d", GRPC_MAX_COMPLETION_QUEUE_PLUCKERS); gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); memset(&ret, 0, sizeof(ret)); diff --git a/src/core/surface/event_string.h b/src/core/surface/event_string.h index e8a8f93518..07c474e3a0 100644 --- a/src/core/surface/event_string.h +++ b/src/core/surface/event_string.h @@ -39,4 +39,4 @@ /* Returns a string describing an event. Must be later freed with gpr_free() */ char *grpc_event_string(grpc_event *ev); -#endif /* GRPC_INTERNAL_CORE_SURFACE_EVENT_STRING_H */ +#endif /* GRPC_INTERNAL_CORE_SURFACE_EVENT_STRING_H */ diff --git a/src/core/surface/init.h b/src/core/surface/init.h index 416874020d..771c30f412 100644 --- a/src/core/surface/init.h +++ b/src/core/surface/init.h @@ -37,4 +37,4 @@ void grpc_security_pre_init(void); int grpc_is_initialized(void); -#endif /* GRPC_INTERNAL_CORE_SURFACE_INIT_H */ +#endif /* GRPC_INTERNAL_CORE_SURFACE_INIT_H */ diff --git a/src/core/surface/init_unsecure.c b/src/core/surface/init_unsecure.c index ddb70cef8e..630d564a7d 100644 --- a/src/core/surface/init_unsecure.c +++ b/src/core/surface/init_unsecure.c @@ -33,5 +33,4 @@ #include "src/core/surface/init.h" -void grpc_security_pre_init(void) { -} +void grpc_security_pre_init(void) {} diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c index c4215a2cfb..80704cbf67 100644 --- a/src/core/surface/lame_client.c +++ b/src/core/surface/lame_client.c @@ -50,6 +50,8 @@ typedef struct { typedef struct { grpc_mdctx *mdctx; grpc_channel *master; + grpc_status_code error_code; + const char *error_message; } channel_data; static void lame_start_transport_stream_op(grpc_call_element *elem, @@ -64,11 +66,11 @@ static void lame_start_transport_stream_op(grpc_call_element *elem, if (op->recv_ops != NULL) { char tmp[GPR_LTOA_MIN_BUFSIZE]; grpc_metadata_batch mdb; - gpr_ltoa(GRPC_STATUS_UNKNOWN, tmp); + gpr_ltoa(chand->error_code, tmp); calld->status.md = grpc_mdelem_from_strings(chand->mdctx, "grpc-status", tmp); calld->details.md = grpc_mdelem_from_strings(chand->mdctx, "grpc-message", - "Rpc sent on a lame channel."); + chand->error_message); calld->status.prev = calld->details.next = NULL; calld->status.next = &calld->details; calld->details.prev = &calld->status; @@ -138,8 +140,21 @@ static const grpc_channel_filter lame_filter = { "lame-client", }; -grpc_channel *grpc_lame_client_channel_create(const char *target) { +#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c) + 1)) + +grpc_channel *grpc_lame_client_channel_create(const char *target, + grpc_status_code error_code, + const char *error_message) { + grpc_channel *channel; + grpc_channel_element *elem; + channel_data *chand; static const grpc_channel_filter *filters[] = {&lame_filter}; - return grpc_channel_create_from_filters(target, filters, 1, NULL, - grpc_mdctx_create(), 1); + channel = grpc_channel_create_from_filters(target, filters, 1, NULL, + grpc_mdctx_create(), 1); + elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); + GPR_ASSERT(elem->filter == &lame_filter); + chand = (channel_data *)elem->channel_data; + chand->error_code = error_code; + chand->error_message = error_message; + return channel; } diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c index c3150250b8..5b03ba95a7 100644 --- a/src/core/surface/secure_channel_create.c +++ b/src/core/surface/secure_channel_create.c @@ -199,13 +199,17 @@ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds, if (grpc_find_security_connector_in_args(args) != NULL) { gpr_log(GPR_ERROR, "Cannot set security context in channel args."); - return grpc_lame_client_channel_create(target); + return grpc_lame_client_channel_create( + target, GRPC_STATUS_INVALID_ARGUMENT, + "Security connector exists in channel args."); } if (grpc_credentials_create_security_connector( creds, target, args, NULL, &connector, &new_args_from_connector) != GRPC_SECURITY_OK) { - return grpc_lame_client_channel_create(target); + return grpc_lame_client_channel_create( + target, GRPC_STATUS_INVALID_ARGUMENT, + "Failed to create security connector."); } mdctx = grpc_mdctx_create(); diff --git a/src/core/surface/server.c b/src/core/surface/server.c index f883275951..1c402418e8 100644 --- a/src/core/surface/server.c +++ b/src/core/surface/server.c @@ -712,7 +712,8 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, chand->server = NULL; chand->channel = NULL; chand->path_key = grpc_mdstr_from_string(metadata_context, ":path", 0); - chand->authority_key = grpc_mdstr_from_string(metadata_context, ":authority", 0); + chand->authority_key = + grpc_mdstr_from_string(metadata_context, ":authority", 0); chand->next = chand->prev = chand; chand->registered_methods = NULL; chand->connectivity_state = GRPC_CHANNEL_IDLE; @@ -974,6 +975,11 @@ void grpc_server_setup_transport(grpc_server *s, grpc_transport *transport, grpc_transport_perform_op(transport, &op); } +void done_published_shutdown(void *done_arg, grpc_cq_completion *storage) { + (void) done_arg; + gpr_free(storage); +} + void grpc_server_shutdown_and_notify(grpc_server *server, grpc_completion_queue *cq, void *tag) { listener *l; @@ -985,6 +991,12 @@ void grpc_server_shutdown_and_notify(grpc_server *server, /* lock, and gather up some stuff to do */ gpr_mu_lock(&server->mu_global); grpc_cq_begin_op(cq); + if (server->shutdown_published) { + grpc_cq_end_op(cq, tag, 1, done_published_shutdown, NULL, + gpr_malloc(sizeof(grpc_cq_completion))); + gpr_mu_unlock(&server->mu_global); + return; + } server->shutdown_tags = gpr_realloc(server->shutdown_tags, sizeof(shutdown_tag) * (server->num_shutdown_tags + 1)); @@ -1134,6 +1146,7 @@ grpc_call_error grpc_server_request_call( return GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE; } grpc_cq_begin_op(cq_for_notification); + details->reserved = NULL; rc->type = BATCH_CALL; rc->server = server; rc->tag = tag; diff --git a/src/core/surface/server_create.c b/src/core/surface/server_create.c index 9237eb5a90..fc7ae820f5 100644 --- a/src/core/surface/server_create.c +++ b/src/core/surface/server_create.c @@ -38,7 +38,7 @@ grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) { const grpc_channel_filter *filters[] = {&grpc_compress_filter}; - (void) reserved; + (void)reserved; return grpc_server_create_from_filters(filters, GPR_ARRAY_SIZE(filters), args); } diff --git a/src/core/surface/surface_trace.h b/src/core/surface/surface_trace.h index 01302bb5d4..2b4728e2b4 100644 --- a/src/core/surface/surface_trace.h +++ b/src/core/surface/surface_trace.h @@ -40,10 +40,10 @@ extern int grpc_surface_trace; #define GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, event) \ - if (grpc_surface_trace) { \ + if (grpc_surface_trace) { \ char *_ev = grpc_event_string(event); \ gpr_log(GPR_INFO, "RETURN_EVENT[%p]: %s", cq, _ev); \ gpr_free(_ev); \ } -#endif /* GRPC_INTERNAL_CORE_SURFACE_SURFACE_TRACE_H */ +#endif /* GRPC_INTERNAL_CORE_SURFACE_SURFACE_TRACE_H */ diff --git a/src/core/transport/chttp2/frame_data.c b/src/core/transport/chttp2/frame_data.c index 40bf2ebd79..474c3d5ee6 100644 --- a/src/core/transport/chttp2/frame_data.c +++ b/src/core/transport/chttp2/frame_data.c @@ -92,10 +92,10 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse( p->frame_type = *cur; switch (p->frame_type) { case 0: - p->is_frame_compressed = 0; /* GPR_FALSE */ + p->is_frame_compressed = 0; /* GPR_FALSE */ break; case 1: - p->is_frame_compressed = 1; /* GPR_TRUE */ + p->is_frame_compressed = 1; /* GPR_TRUE */ break; default: gpr_log(GPR_ERROR, "Bad GRPC frame type 0x%02x", p->frame_type); diff --git a/src/core/transport/chttp2/parsing.c b/src/core/transport/chttp2/parsing.c index d84960009b..dc5eb18e42 100644 --- a/src/core/transport/chttp2/parsing.c +++ b/src/core/transport/chttp2/parsing.c @@ -177,10 +177,9 @@ void grpc_chttp2_publish_reads( "parsed", transport_parsing, stream_global, max_recv_bytes, -(gpr_int64)stream_parsing->incoming_window_delta); stream_global->incoming_window -= stream_parsing->incoming_window_delta; - GPR_ASSERT(stream_global->max_recv_bytes >= - stream_parsing->incoming_window_delta); - stream_global->max_recv_bytes -= - stream_parsing->incoming_window_delta; + GPR_ASSERT(stream_global->max_recv_bytes >= + stream_parsing->incoming_window_delta); + stream_global->max_recv_bytes -= stream_parsing->incoming_window_delta; stream_parsing->incoming_window_delta = 0; grpc_chttp2_list_add_writable_stream(transport_global, stream_global); } diff --git a/src/core/transport/chttp2/stream_lists.c b/src/core/transport/chttp2/stream_lists.c index 9c3ad7a777..38c6052f9c 100644 --- a/src/core/transport/chttp2/stream_lists.c +++ b/src/core/transport/chttp2/stream_lists.c @@ -363,7 +363,7 @@ void grpc_chttp2_register_stream(grpc_chttp2_transport *t, } int grpc_chttp2_unregister_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream *s) { + grpc_chttp2_stream *s) { stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_ALL_STREAMS); return stream_list_empty(t, GRPC_CHTTP2_LIST_ALL_STREAMS); } diff --git a/src/core/transport/chttp2/stream_map.c b/src/core/transport/chttp2/stream_map.c index 0ec2f27291..bd16153ed1 100644 --- a/src/core/transport/chttp2/stream_map.c +++ b/src/core/transport/chttp2/stream_map.c @@ -123,8 +123,7 @@ void grpc_chttp2_stream_map_move_into(grpc_chttp2_stream_map *src, dst->values = gpr_realloc(dst->values, dst->capacity * sizeof(void *)); } memcpy(dst->keys + dst->count, src->keys, src->count * sizeof(gpr_uint32)); - memcpy(dst->values + dst->count, src->values, - src->count * sizeof(void*)); + memcpy(dst->values + dst->count, src->values, src->count * sizeof(void *)); dst->count += src->count; dst->free += src->free; src->count = 0; diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c index b55e81fdca..123061b3fc 100644 --- a/src/core/transport/chttp2/writing.c +++ b/src/core/transport/chttp2/writing.c @@ -112,13 +112,18 @@ int grpc_chttp2_unlocking_check_writes( } } - if (!stream_global->read_closed && stream_global->unannounced_incoming_window > 0) { - stream_writing->announce_window = stream_global->unannounced_incoming_window; - GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global, - incoming_window, stream_global->unannounced_incoming_window); - GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global, - unannounced_incoming_window, -(gpr_int64)stream_global->unannounced_incoming_window); - stream_global->incoming_window += stream_global->unannounced_incoming_window; + if (!stream_global->read_closed && + stream_global->unannounced_incoming_window > 0) { + stream_writing->announce_window = + stream_global->unannounced_incoming_window; + GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( + "write", transport_global, stream_global, incoming_window, + stream_global->unannounced_incoming_window); + GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( + "write", transport_global, stream_global, unannounced_incoming_window, + -(gpr_int64)stream_global->unannounced_incoming_window); + stream_global->incoming_window += + stream_global->unannounced_incoming_window; stream_global->unannounced_incoming_window = 0; grpc_chttp2_list_add_incoming_window_updated(transport_global, stream_global); @@ -179,18 +184,20 @@ static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing) { while ( grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) { - if (stream_writing->sopb.nops > 0 || stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) { + if (stream_writing->sopb.nops > 0 || + stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) { grpc_chttp2_encode(stream_writing->sopb.ops, stream_writing->sopb.nops, stream_writing->send_closed != GRPC_DONT_SEND_CLOSED, - stream_writing->id, &transport_writing->hpack_compressor, + stream_writing->id, + &transport_writing->hpack_compressor, &transport_writing->outbuf); stream_writing->sopb.nops = 0; } if (stream_writing->announce_window > 0) { gpr_slice_buffer_add( &transport_writing->outbuf, - grpc_chttp2_window_update_create( - stream_writing->id, stream_writing->announce_window)); + grpc_chttp2_window_update_create(stream_writing->id, + stream_writing->announce_window)); stream_writing->announce_window = 0; } if (stream_writing->send_closed == GRPC_SEND_CLOSED_WITH_RST_STREAM) { diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index a9f91b64d5..1bbd210e46 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -116,7 +116,7 @@ static void close_from_api(grpc_chttp2_transport_global *transport_global, static void add_to_pollset_locked(grpc_chttp2_transport *t, grpc_pollset *pollset); static void add_to_pollset_set_locked(grpc_chttp2_transport *t, - grpc_pollset_set *pollset_set); + grpc_pollset_set *pollset_set); /** Start new streams that have been created if we can */ static void maybe_start_some_streams( @@ -368,11 +368,10 @@ static int init_stream(grpc_transport *gt, grpc_stream *gs, s->global.outgoing_window = t->global.settings[GRPC_PEER_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - s->global.max_recv_bytes = - s->parsing.incoming_window = + s->global.max_recv_bytes = s->parsing.incoming_window = s->global.incoming_window = - t->global.settings[GRPC_SENT_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + t->global.settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; *t->accepting_stream = s; grpc_chttp2_stream_map_add(&t->parsing_stream_map, s->global.id, s); s->global.in_stream_map = 1; @@ -580,7 +579,7 @@ static void maybe_start_some_streams( stream_global->incoming_window = transport_global->settings[GRPC_SENT_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - stream_global->max_recv_bytes = + stream_global->max_recv_bytes = GPR_MAX(stream_global->incoming_window, stream_global->max_recv_bytes); grpc_chttp2_stream_map_add( &TRANSPORT_FROM_GLOBAL(transport_global)->new_stream_map, @@ -590,7 +589,6 @@ static void maybe_start_some_streams( grpc_chttp2_list_add_incoming_window_updated(transport_global, stream_global); grpc_chttp2_list_add_writable_stream(transport_global, stream_global); - } /* cancel out streams that will never be started */ while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID && @@ -648,12 +646,14 @@ static void perform_stream_op_locked( stream_global->publish_sopb->nops = 0; stream_global->publish_state = op->recv_state; if (stream_global->max_recv_bytes < op->max_recv_bytes) { - GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("op", transport_global, stream_global, - max_recv_bytes, op->max_recv_bytes - stream_global->max_recv_bytes); + GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( + "op", transport_global, stream_global, max_recv_bytes, + op->max_recv_bytes - stream_global->max_recv_bytes); GRPC_CHTTP2_FLOWCTL_TRACE_STREAM( "op", transport_global, stream_global, unannounced_incoming_window, op->max_recv_bytes - stream_global->max_recv_bytes); - stream_global->unannounced_incoming_window += op->max_recv_bytes - stream_global->max_recv_bytes; + stream_global->unannounced_incoming_window += + op->max_recv_bytes - stream_global->max_recv_bytes; stream_global->max_recv_bytes = op->max_recv_bytes; } grpc_chttp2_incoming_metadata_live_op_buffer_end( @@ -1175,7 +1175,7 @@ static void add_to_pollset_locked(grpc_chttp2_transport *t, } static void add_to_pollset_set_locked(grpc_chttp2_transport *t, - grpc_pollset_set *pollset_set) { + grpc_pollset_set *pollset_set) { if (t->ep) { grpc_endpoint_add_to_pollset_set(t->ep, pollset_set); } diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c index 44d32b6cb2..f92e87e9dd 100644 --- a/src/core/transport/metadata.c +++ b/src/core/transport/metadata.c @@ -133,8 +133,8 @@ static void unlock(grpc_mdctx *ctx) { case), since otherwise we can be stuck waiting for a garbage collection that will never happen. */ if (ctx->refs == 0) { - /* uncomment if you're having trouble diagnosing an mdelem leak to make - things clearer (slows down destruction a lot, however) */ +/* uncomment if you're having trouble diagnosing an mdelem leak to make + things clearer (slows down destruction a lot, however) */ #ifdef GRPC_METADATA_REFCOUNT_DEBUG gc_mdtab(ctx); #endif @@ -311,7 +311,8 @@ static void slice_unref(void *p) { unlock(ctx); } -grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str, int canonicalize_key) { +grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str, + int canonicalize_key) { if (canonicalize_key) { size_t len; size_t i; @@ -522,9 +523,9 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx, grpc_mdelem *grpc_mdelem_from_strings(grpc_mdctx *ctx, const char *key, const char *value) { - return grpc_mdelem_from_metadata_strings(ctx, - grpc_mdstr_from_string(ctx, key, 0), - grpc_mdstr_from_string(ctx, value, 0)); + return grpc_mdelem_from_metadata_strings( + ctx, grpc_mdstr_from_string(ctx, key, 0), + grpc_mdstr_from_string(ctx, value, 0)); } grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key, diff --git a/src/core/transport/metadata.h b/src/core/transport/metadata.h index 15ef9bb555..a7af49ba55 100644 --- a/src/core/transport/metadata.h +++ b/src/core/transport/metadata.h @@ -95,7 +95,8 @@ size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *mdctx); /* Constructors for grpc_mdstr instances; take a variety of data types that clients may have handy */ -grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str, int perform_key_canonicalization); +grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str, + int perform_key_canonicalization); /* Unrefs the slice. */ grpc_mdstr *grpc_mdstr_from_slice(grpc_mdctx *ctx, gpr_slice slice); grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *str, @@ -179,4 +180,4 @@ void grpc_mdctx_unlock(grpc_mdctx *ctx); #define GRPC_MDSTR_KV_HASH(k_hash, v_hash) (GPR_ROTL((k_hash), 2) ^ (v_hash)) -#endif /* GRPC_INTERNAL_CORE_TRANSPORT_METADATA_H */ +#endif /* GRPC_INTERNAL_CORE_TRANSPORT_METADATA_H */ diff --git a/src/core/transport/stream_op.c b/src/core/transport/stream_op.c index 0a9669b0ab..038586d48e 100644 --- a/src/core/transport/stream_op.c +++ b/src/core/transport/stream_op.c @@ -203,8 +203,8 @@ void grpc_metadata_batch_assert_ok(grpc_metadata_batch *batch) { #endif /* NDEBUG */ void grpc_metadata_batch_init(grpc_metadata_batch *batch) { - batch->list.head = batch->list.tail = batch->garbage.head = batch->garbage.tail = - NULL; + batch->list.head = batch->list.tail = batch->garbage.head = + batch->garbage.tail = NULL; batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); } @@ -288,7 +288,7 @@ void grpc_metadata_batch_merge(grpc_metadata_batch *target, } void grpc_metadata_batch_move(grpc_metadata_batch *dst, - grpc_metadata_batch *src) { + grpc_metadata_batch *src) { *dst = *src; memset(src, 0, sizeof(grpc_metadata_batch)); } diff --git a/src/core/tsi/fake_transport_security.c b/src/core/tsi/fake_transport_security.c index 9ce1ddb95e..29127c4269 100644 --- a/src/core/tsi/fake_transport_security.c +++ b/src/core/tsi/fake_transport_security.c @@ -121,7 +121,7 @@ static void store32_little_endian(gpr_uint32 value, unsigned char* buf) { buf[3] = (unsigned char)(value >> 24) & 0xFF; buf[2] = (unsigned char)(value >> 16) & 0xFF; buf[1] = (unsigned char)(value >> 8) & 0xFF; - buf[0] = (unsigned char)(value) & 0xFF; + buf[0] = (unsigned char)(value)&0xFF; } static void tsi_fake_frame_reset(tsi_fake_frame* frame, int needs_draining) { @@ -370,7 +370,8 @@ static void fake_protector_destroy(tsi_frame_protector* self) { static const tsi_frame_protector_vtable frame_protector_vtable = { fake_protector_protect, fake_protector_protect_flush, - fake_protector_unprotect, fake_protector_destroy, }; + fake_protector_unprotect, fake_protector_destroy, +}; /* --- tsi_handshaker methods implementation. ---*/ @@ -393,7 +394,8 @@ static tsi_result fake_handshaker_get_bytes_to_send_to_peer( next_message_to_send = TSI_FAKE_HANDSHAKE_MESSAGE_MAX; } if (tsi_tracing_enabled) { - gpr_log(GPR_INFO, "%s prepared %s.", impl->is_client ? "Client" : "Server", + gpr_log(GPR_INFO, "%s prepared %s.", + impl->is_client ? "Client" : "Server", tsi_fake_handshake_message_to_string(impl->next_message_to_send)); } impl->next_message_to_send = next_message_to_send; @@ -493,7 +495,8 @@ static const tsi_handshaker_vtable handshaker_vtable = { fake_handshaker_get_result, fake_handshaker_extract_peer, fake_handshaker_create_frame_protector, - fake_handshaker_destroy, }; + fake_handshaker_destroy, +}; tsi_handshaker* tsi_create_fake_handshaker(int is_client) { tsi_fake_handshaker* impl = calloc(1, sizeof(tsi_fake_handshaker)); diff --git a/src/core/tsi/fake_transport_security.h b/src/core/tsi/fake_transport_security.h index af9730b90e..1fa11349fb 100644 --- a/src/core/tsi/fake_transport_security.h +++ b/src/core/tsi/fake_transport_security.h @@ -58,4 +58,4 @@ tsi_frame_protector* tsi_create_fake_protector( } #endif -#endif /* GRPC_INTERNAL_CORE_TSI_FAKE_TRANSPORT_SECURITY_H */ +#endif /* GRPC_INTERNAL_CORE_TSI_FAKE_TRANSPORT_SECURITY_H */ diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c index 609fc06ed5..0b416f6c9d 100644 --- a/src/core/tsi/ssl_transport_security.c +++ b/src/core/tsi/ssl_transport_security.c @@ -43,7 +43,7 @@ #include "src/core/tsi/transport_security.h" #include <openssl/bio.h> -#include <openssl/crypto.h> /* For OPENSSL_free */ +#include <openssl/crypto.h> /* For OPENSSL_free */ #include <openssl/err.h> #include <openssl/ssl.h> #include <openssl/x509.h> @@ -54,7 +54,6 @@ #define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND 16384 #define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND 1024 - /* Putting a macro like this and littering the source file with #if is really bad practice. TODO(jboeuf): refactor all the #if / #endif in a separate module. */ @@ -116,7 +115,7 @@ typedef struct { /* --- Library Initialization. ---*/ static gpr_once init_openssl_once = GPR_ONCE_INIT; -static gpr_mu *openssl_mutexes = NULL; +static gpr_mu* openssl_mutexes = NULL; static void openssl_locking_cb(int mode, int type, const char* file, int line) { if (mode & CRYPTO_LOCK) { @@ -195,7 +194,7 @@ static void ssl_info_callback(const SSL* ssl, int where, int ret) { /* Returns 1 if name looks like an IP address, 0 otherwise. This is a very rough heuristic as it does not handle IPV6 or things like: 0300.0250.00.01, 0xC0.0Xa8.0x0.0x1, 000030052000001, 0xc0.052000001 */ -static int looks_like_ip_address(const char *name) { +static int looks_like_ip_address(const char* name) { size_t i; size_t dot_count = 0; size_t num_size = 0; @@ -215,7 +214,6 @@ static int looks_like_ip_address(const char *name) { return 1; } - /* Gets the subject CN from an X509 cert. */ static tsi_result ssl_get_x509_common_name(X509* cert, unsigned char** utf8, size_t* utf8_size) { @@ -630,7 +628,8 @@ static tsi_result build_alpn_protocol_name_list( } /* Safety check. */ if ((current < *protocol_name_list) || - ((gpr_uintptr)(current - *protocol_name_list) != *protocol_name_list_length)) { + ((gpr_uintptr)(current - *protocol_name_list) != + *protocol_name_list_length)) { return TSI_INTERNAL_ERROR; } return TSI_OK; @@ -768,7 +767,8 @@ static void ssl_protector_destroy(tsi_frame_protector* self) { static const tsi_frame_protector_vtable frame_protector_vtable = { ssl_protector_protect, ssl_protector_protect_flush, ssl_protector_unprotect, - ssl_protector_destroy, }; + ssl_protector_destroy, +}; /* --- tsi_handshaker methods implementation. ---*/ @@ -948,7 +948,8 @@ static const tsi_handshaker_vtable handshaker_vtable = { ssl_handshaker_get_result, ssl_handshaker_extract_peer, ssl_handshaker_create_frame_protector, - ssl_handshaker_destroy, }; + ssl_handshaker_destroy, +}; /* --- tsi_ssl_handshaker_factory common methods. --- */ @@ -1075,9 +1076,11 @@ static void ssl_client_handshaker_factory_destroy( free(impl); } -static int client_handshaker_factory_npn_callback( - SSL* ssl, unsigned char** out, unsigned char* outlen, - const unsigned char* in, unsigned int inlen, void* arg) { +static int client_handshaker_factory_npn_callback(SSL* ssl, unsigned char** out, + unsigned char* outlen, + const unsigned char* in, + unsigned int inlen, + void* arg) { tsi_ssl_client_handshaker_factory* factory = (tsi_ssl_client_handshaker_factory*)arg; return select_protocol_list((const unsigned char**)out, outlen, @@ -1121,7 +1124,7 @@ static void ssl_server_handshaker_factory_destroy( static int does_entry_match_name(const char* entry, size_t entry_length, const char* name) { - const char *dot; + const char* dot; const char* name_subdomain = NULL; size_t name_length = strlen(name); size_t name_subdomain_length; @@ -1153,7 +1156,7 @@ static int does_entry_match_name(const char* entry, size_t entry_length, if (name_subdomain_length < 2) return 0; name_subdomain++; /* Starts after the dot. */ name_subdomain_length--; - entry += 2; /* Remove *. */ + entry += 2; /* Remove *. */ entry_length -= 2; dot = strchr(name_subdomain, '.'); if ((dot == NULL) || (dot == &name_subdomain[name_subdomain_length - 1])) { @@ -1170,7 +1173,7 @@ static int does_entry_match_name(const char* entry, size_t entry_length, static int ssl_server_handshaker_factory_servername_callback(SSL* ssl, int* ap, void* arg) { tsi_ssl_server_handshaker_factory* impl = - (tsi_ssl_server_handshaker_factory*)arg; + (tsi_ssl_server_handshaker_factory*)arg; size_t i = 0; const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (servername == NULL || strlen(servername) == 0) { diff --git a/src/core/tsi/ssl_transport_security.h b/src/core/tsi/ssl_transport_security.h index 4bf6c81b75..cdf4f294be 100644 --- a/src/core/tsi/ssl_transport_security.h +++ b/src/core/tsi/ssl_transport_security.h @@ -170,4 +170,4 @@ int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name); } #endif -#endif /* GRPC_INTERNAL_CORE_TSI_SSL_TRANSPORT_SECURITY_H */ +#endif /* GRPC_INTERNAL_CORE_TSI_SSL_TRANSPORT_SECURITY_H */ diff --git a/src/core/tsi/transport_security.h b/src/core/tsi/transport_security.h index 4cd0ec2cfb..34283f2f9c 100644 --- a/src/core/tsi/transport_security.h +++ b/src/core/tsi/transport_security.h @@ -108,4 +108,4 @@ char* tsi_strdup(const char* src); /* Sadly, no strdup in C89. */ } #endif -#endif /* GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_H */ +#endif /* GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_H */ diff --git a/src/core/tsi/transport_security_interface.h b/src/core/tsi/transport_security_interface.h index e27e6b9fc9..03a51683a2 100644 --- a/src/core/tsi/transport_security_interface.h +++ b/src/core/tsi/transport_security_interface.h @@ -341,4 +341,4 @@ void tsi_handshaker_destroy(tsi_handshaker* self); } #endif -#endif /* GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H */ +#endif /* GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H */ diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc index 0582b59a6d..17f31c22cb 100644 --- a/src/cpp/client/channel.cc +++ b/src/cpp/client/channel.cc @@ -71,7 +71,7 @@ Call Channel::CreateCall(const RpcMethod& method, ClientContext* context, } else { const char* host_str = NULL; if (!context->authority().empty()) { - host_str = context->authority().c_str(); + host_str = context->authority_.c_str(); } else if (!host_.empty()) { host_str = host_.c_str(); } @@ -98,9 +98,8 @@ void Channel::PerformOpsOnCall(CallOpSetInterface* ops, Call* call) { } void* Channel::RegisterMethod(const char* method) { - return grpc_channel_register_call(c_channel_, method, - host_.empty() ? NULL : host_.c_str(), - nullptr); + return grpc_channel_register_call( + c_channel_, method, host_.empty() ? NULL : host_.c_str(), nullptr); } grpc_connectivity_state Channel::GetState(bool try_to_connect) { @@ -117,6 +116,7 @@ class TagSaver GRPC_FINAL : public CompletionQueueTag { delete this; return true; } + private: void* tag_; }; diff --git a/src/cpp/client/channel.h b/src/cpp/client/channel.h index cb8e8d98d2..7e406ad788 100644 --- a/src/cpp/client/channel.h +++ b/src/cpp/client/channel.h @@ -58,9 +58,8 @@ class Channel GRPC_FINAL : public GrpcLibrary, public ChannelInterface { void* RegisterMethod(const char* method) GRPC_OVERRIDE; Call CreateCall(const RpcMethod& method, ClientContext* context, - CompletionQueue* cq) GRPC_OVERRIDE; - void PerformOpsOnCall(CallOpSetInterface* ops, - Call* call) GRPC_OVERRIDE; + CompletionQueue* cq) GRPC_OVERRIDE; + void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) GRPC_OVERRIDE; grpc_connectivity_state GetState(bool try_to_connect) GRPC_OVERRIDE; diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc index 21d01b739d..5ae772f096 100644 --- a/src/cpp/client/create_channel.cc +++ b/src/cpp/client/create_channel.cc @@ -52,6 +52,8 @@ std::shared_ptr<ChannelInterface> CreateChannel( user_agent_prefix.str()); return creds ? creds->CreateChannel(target, cp_args) : std::shared_ptr<ChannelInterface>( - new Channel(grpc_lame_client_channel_create(NULL))); + new Channel(grpc_lame_client_channel_create( + NULL, GRPC_STATUS_INVALID_ARGUMENT, + "Invalid credentials."))); } } // namespace grpc diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h index ddf69911b5..c2b8d43a15 100644 --- a/src/cpp/client/secure_credentials.h +++ b/src/cpp/client/secure_credentials.h @@ -59,4 +59,3 @@ class SecureCredentials GRPC_FINAL : public Credentials { } // namespace grpc #endif // GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H - diff --git a/src/cpp/common/auth_property_iterator.cc b/src/cpp/common/auth_property_iterator.cc index ba88983515..d3bfd5cb6b 100644 --- a/src/cpp/common/auth_property_iterator.cc +++ b/src/cpp/common/auth_property_iterator.cc @@ -64,8 +64,7 @@ AuthPropertyIterator AuthPropertyIterator::operator++(int) { return tmp; } -bool AuthPropertyIterator::operator==( - const AuthPropertyIterator& rhs) const { +bool AuthPropertyIterator::operator==(const AuthPropertyIterator& rhs) const { if (property_ == nullptr || rhs.property_ == nullptr) { return property_ == rhs.property_; } else { @@ -73,8 +72,7 @@ bool AuthPropertyIterator::operator==( } } -bool AuthPropertyIterator::operator!=( - const AuthPropertyIterator& rhs) const { +bool AuthPropertyIterator::operator!=(const AuthPropertyIterator& rhs) const { return !operator==(rhs); } diff --git a/src/cpp/proto/proto_utils.cc b/src/cpp/proto/proto_utils.cc index 63f4a3a0bc..05470ec627 100644 --- a/src/cpp/proto/proto_utils.cc +++ b/src/cpp/proto/proto_utils.cc @@ -154,18 +154,18 @@ class GrpcBufferReader GRPC_FINAL namespace grpc { -Status SerializeProto(const grpc::protobuf::Message& msg, grpc_byte_buffer** bp) { +Status SerializeProto(const grpc::protobuf::Message& msg, + grpc_byte_buffer** bp) { GrpcBufferWriter writer(bp); return msg.SerializeToZeroCopyStream(&writer) ? Status::OK - : Status(StatusCode::INVALID_ARGUMENT, - "Failed to serialize message"); + : Status(StatusCode::INTERNAL, "Failed to serialize message"); } Status DeserializeProto(grpc_byte_buffer* buffer, grpc::protobuf::Message* msg, int max_message_size) { if (!buffer) { - return Status(StatusCode::INVALID_ARGUMENT, "No payload"); + return Status(StatusCode::INTERNAL, "No payload"); } GrpcBufferReader reader(buffer); ::grpc::protobuf::io::CodedInputStream decoder(&reader); @@ -173,11 +173,10 @@ Status DeserializeProto(grpc_byte_buffer* buffer, grpc::protobuf::Message* msg, decoder.SetTotalBytesLimit(max_message_size, max_message_size); } if (!msg->ParseFromCodedStream(&decoder)) { - return Status(StatusCode::INVALID_ARGUMENT, - msg->InitializationErrorString()); + return Status(StatusCode::INTERNAL, msg->InitializationErrorString()); } if (!decoder.ConsumedEntireMessage()) { - return Status(StatusCode::INVALID_ARGUMENT, "Did not read entire message"); + return Status(StatusCode::INTERNAL, "Did not read entire message"); } return Status::OK; } diff --git a/src/cpp/server/create_default_thread_pool.cc b/src/cpp/server/create_default_thread_pool.cc index 81c84474d8..9f59d254f1 100644 --- a/src/cpp/server/create_default_thread_pool.cc +++ b/src/cpp/server/create_default_thread_pool.cc @@ -39,9 +39,9 @@ namespace grpc { ThreadPoolInterface* CreateDefaultThreadPool() { - int cores = gpr_cpu_num_cores(); - if (!cores) cores = 4; - return new DynamicThreadPool(cores); + int cores = gpr_cpu_num_cores(); + if (!cores) cores = 4; + return new DynamicThreadPool(cores); } } // namespace grpc diff --git a/src/cpp/server/dynamic_thread_pool.cc b/src/cpp/server/dynamic_thread_pool.cc index f58d0420df..b475f43b1d 100644 --- a/src/cpp/server/dynamic_thread_pool.cc +++ b/src/cpp/server/dynamic_thread_pool.cc @@ -36,10 +36,10 @@ #include <grpc++/dynamic_thread_pool.h> namespace grpc { -DynamicThreadPool::DynamicThread::DynamicThread(DynamicThreadPool *pool): - pool_(pool), - thd_(new grpc::thread(&DynamicThreadPool::DynamicThread::ThreadFunc, this)) { -} +DynamicThreadPool::DynamicThread::DynamicThread(DynamicThreadPool* pool) + : pool_(pool), + thd_(new grpc::thread(&DynamicThreadPool::DynamicThread::ThreadFunc, + this)) {} DynamicThreadPool::DynamicThread::~DynamicThread() { thd_->join(); thd_.reset(); @@ -57,7 +57,7 @@ void DynamicThreadPool::DynamicThread::ThreadFunc() { pool_->shutdown_cv_.notify_one(); } } - + void DynamicThreadPool::ThreadFunc() { for (;;) { // Wait until work is available or we are shutting down. @@ -65,7 +65,7 @@ void DynamicThreadPool::ThreadFunc() { if (!shutdown_ && callbacks_.empty()) { // If there are too many threads waiting, then quit this thread if (threads_waiting_ >= reserve_threads_) { - break; + break; } threads_waiting_++; cv_.wait(lock); @@ -84,9 +84,11 @@ void DynamicThreadPool::ThreadFunc() { } } -DynamicThreadPool::DynamicThreadPool(int reserve_threads) : - shutdown_(false), reserve_threads_(reserve_threads), nthreads_(0), - threads_waiting_(0) { +DynamicThreadPool::DynamicThreadPool(int reserve_threads) + : shutdown_(false), + reserve_threads_(reserve_threads), + nthreads_(0), + threads_waiting_(0) { for (int i = 0; i < reserve_threads_; i++) { grpc::lock_guard<grpc::mutex> lock(mu_); nthreads_++; @@ -96,10 +98,10 @@ DynamicThreadPool::DynamicThreadPool(int reserve_threads) : void DynamicThreadPool::ReapThreads(std::list<DynamicThread*>* tlist) { for (auto t = tlist->begin(); t != tlist->end(); t = tlist->erase(t)) { - delete *t; + delete *t; } } - + DynamicThreadPool::~DynamicThreadPool() { grpc::unique_lock<grpc::mutex> lock(mu_); shutdown_ = true; diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc index 32c45e2280..f203cf7f49 100644 --- a/src/cpp/server/secure_server_credentials.cc +++ b/src/cpp/server/secure_server_credentials.cc @@ -35,8 +35,8 @@ namespace grpc { -int SecureServerCredentials::AddPortToServer( - const grpc::string& addr, grpc_server* server) { +int SecureServerCredentials::AddPortToServer(const grpc::string& addr, + grpc_server* server) { return grpc_server_add_secure_http2_port(server, addr.c_str(), creds_); } diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc index 90f3854a72..e039c07374 100644 --- a/src/cpp/server/server.cc +++ b/src/cpp/server/server.cc @@ -90,6 +90,26 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag { return mrd; } + static bool AsyncWait(CompletionQueue* cq, SyncRequest** req, bool* ok, + gpr_timespec deadline) { + void* tag = nullptr; + *ok = false; + switch (cq->AsyncNext(&tag, ok, deadline)) { + case CompletionQueue::TIMEOUT: + *req = nullptr; + return true; + case CompletionQueue::SHUTDOWN: + *req = nullptr; + return false; + case CompletionQueue::GOT_EVENT: + *req = static_cast<SyncRequest*>(tag); + GPR_ASSERT((*req)->in_flight_); + return true; + } + gpr_log(GPR_ERROR, "Should never reach here"); + abort(); + } + void SetupRequest() { cq_ = grpc_completion_queue_create(nullptr); } void TeardownRequest() { @@ -230,18 +250,17 @@ Server::~Server() { delete sync_methods_; } -bool Server::RegisterService(const grpc::string *host, RpcService* service) { +bool Server::RegisterService(const grpc::string* host, RpcService* service) { for (int i = 0; i < service->GetMethodCount(); ++i) { RpcServiceMethod* method = service->GetMethod(i); - void* tag = grpc_server_register_method( - server_, method->name(), host ? host->c_str() : nullptr); + void* tag = grpc_server_register_method(server_, method->name(), + host ? host->c_str() : nullptr); if (!tag) { gpr_log(GPR_DEBUG, "Attempt to register %s multiple times", method->name()); return false; } - SyncRequest request(method, tag); - sync_methods_->emplace_back(request); + sync_methods_->emplace_back(method, tag); } return true; } @@ -286,7 +305,10 @@ bool Server::Start() { if (!has_generic_service_) { unknown_method_.reset(new RpcServiceMethod( "unknown", RpcMethod::BIDI_STREAMING, new UnknownMethodHandler)); - sync_methods_->emplace_back(unknown_method_.get(), nullptr); + // Use of emplace_back with just constructor arguments is not accepted here + // by gcc-4.4 because it can't match the anonymous nullptr with a proper + // constructor implicitly. Construct the object and use push_back. + sync_methods_->push_back(SyncRequest(unknown_method_.get(), nullptr)); } // Start processing rpcs. if (!sync_methods_->empty()) { @@ -301,12 +323,27 @@ bool Server::Start() { return true; } -void Server::Shutdown() { +void Server::ShutdownInternal(gpr_timespec deadline) { grpc::unique_lock<grpc::mutex> lock(mu_); if (started_ && !shutdown_) { shutdown_ = true; grpc_server_shutdown_and_notify(server_, cq_.cq(), new ShutdownRequest()); cq_.Shutdown(); + // Spin, eating requests until the completion queue is completely shutdown. + // If the deadline expires then cancel anything that's pending and keep + // spinning forever until the work is actually drained. + // Since nothing else needs to touch state guarded by mu_, holding it + // through this loop is fine. + SyncRequest* request; + bool ok; + while (SyncRequest::AsyncWait(&cq_, &request, &ok, deadline)) { + if (request == NULL) { // deadline expired + grpc_server_cancel_all_calls(server_); + deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); + } else if (ok) { + SyncRequest::CallData call_data(this, request); + } + } // Wait for running callbacks to finish. while (num_running_cb_ != 0) { diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc index 09118879f4..0b11d86173 100644 --- a/src/cpp/server/server_builder.cc +++ b/src/cpp/server/server_builder.cc @@ -59,14 +59,16 @@ void ServerBuilder::RegisterAsyncService(AsynchronousService* service) { async_services_.emplace_back(new NamedService<AsynchronousService>(service)); } -void ServerBuilder::RegisterService( - const grpc::string& addr, SynchronousService* service) { - services_.emplace_back(new NamedService<RpcService>(addr, service->service())); +void ServerBuilder::RegisterService(const grpc::string& addr, + SynchronousService* service) { + services_.emplace_back( + new NamedService<RpcService>(addr, service->service())); } -void ServerBuilder::RegisterAsyncService( - const grpc::string& addr, AsynchronousService* service) { - async_services_.emplace_back(new NamedService<AsynchronousService>(addr, service)); +void ServerBuilder::RegisterAsyncService(const grpc::string& addr, + AsynchronousService* service) { + async_services_.emplace_back( + new NamedService<AsynchronousService>(addr, service)); } void ServerBuilder::RegisterAsyncGenericService(AsyncGenericService* service) { @@ -119,9 +121,10 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() { return nullptr; } } - for (auto service = async_services_.begin(); - service != async_services_.end(); service++) { - if (!server->RegisterAsyncService((*service)->host.get(), (*service)->service)) { + for (auto service = async_services_.begin(); service != async_services_.end(); + service++) { + if (!server->RegisterAsyncService((*service)->host.get(), + (*service)->service)) { return nullptr; } } diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc index bb34040a2f..03461ddda5 100644 --- a/src/cpp/server/server_context.cc +++ b/src/cpp/server/server_context.cc @@ -50,7 +50,12 @@ namespace grpc { class ServerContext::CompletionOp GRPC_FINAL : public CallOpSetInterface { public: // initial refs: one in the server context, one in the cq - CompletionOp() : has_tag_(false), tag_(nullptr), refs_(2), finalized_(false), cancelled_(0) {} + CompletionOp() + : has_tag_(false), + tag_(nullptr), + refs_(2), + finalized_(false), + cancelled_(0) {} void FillOps(grpc_op* ops, size_t* nops) GRPC_OVERRIDE; bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE; diff --git a/src/csharp/Grpc.Auth/AuthInterceptors.cs b/src/csharp/Grpc.Auth/AuthInterceptors.cs new file mode 100644 index 0000000000..61338f7f0e --- /dev/null +++ b/src/csharp/Grpc.Auth/AuthInterceptors.cs @@ -0,0 +1,84 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Threading; + +using Google.Apis.Auth.OAuth2; +using Grpc.Core; +using Grpc.Core.Utils; + +namespace Grpc.Auth +{ + /// <summary> + /// Factory methods to create authorization interceptors. + /// </summary> + public static class AuthInterceptors + { + private const string AuthorizationHeader = "Authorization"; + private const string Schema = "Bearer"; + + /// <summary> + /// Creates interceptor that will obtain access token from any credential type that implements + /// <c>ITokenAccess</c>. (e.g. <c>GoogleCredential</c>). + /// </summary> + public static HeaderInterceptor FromCredential(ITokenAccess credential) + { + return new HeaderInterceptor((method, authUri, metadata) => + { + // TODO(jtattermusch): Rethink synchronous wait to obtain the result. + var accessToken = credential.GetAccessTokenForRequestAsync(authUri, CancellationToken.None) + .ConfigureAwait(false).GetAwaiter().GetResult(); + metadata.Add(CreateBearerTokenHeader(accessToken)); + }); + } + + /// <summary> + /// Creates OAuth2 interceptor that will use given access token as authorization. + /// </summary> + /// <param name="accessToken">OAuth2 access token.</param> + public static HeaderInterceptor FromAccessToken(string accessToken) + { + Preconditions.CheckNotNull(accessToken); + return new HeaderInterceptor((method, authUri, metadata) => + { + metadata.Add(CreateBearerTokenHeader(accessToken)); + }); + } + + private static Metadata.Entry CreateBearerTokenHeader(string accessToken) + { + return new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken); + } + } +} diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj index 930a34b0c3..4fb087d4a3 100644 --- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj +++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj @@ -3,8 +3,6 @@ <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <ProductVersion>10.0.0</ProductVersion> - <SchemaVersion>2.0</SchemaVersion> <ProjectGuid>{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}</ProjectGuid> <OutputType>Library</OutputType> <RootNamespace>Grpc.Auth</RootNamespace> @@ -41,57 +39,47 @@ <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile> </PropertyGroup> <ItemGroup> - <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="System" /> + <Reference Include="System.Net" /> + <Reference Include="System.Net.Http" /> + <Reference Include="System.Net.Http.WebRequest" /> + <Reference Include="BouncyCastle.Crypto"> <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath> </Reference> - <Reference Include="Google.Apis.Auth, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="Google.Apis.Auth"> <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath> </Reference> - <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.3.19383, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="Google.Apis.Auth.PlatformServices"> <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath> </Reference> - <Reference Include="Google.Apis.Core, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="Google.Apis.Core"> <HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath> </Reference> - <Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="Microsoft.Threading.Tasks"> <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath> </Reference> - <Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="Microsoft.Threading.Tasks.Extensions"> <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath> </Reference> - <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop"> <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath> </Reference> - <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="Newtonsoft.Json"> <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> </Reference> - <Reference Include="System" /> - <Reference Include="System.Net" /> - <Reference Include="System.Net.Http" /> - <Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="System.Net.Http.Extensions"> <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath> </Reference> - <Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> + <Reference Include="System.Net.Http.Primitives"> <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath> </Reference> - <Reference Include="System.Net.Http.WebRequest" /> </ItemGroup> <ItemGroup> <Compile Include="..\Grpc.Core\Version.cs"> <Link>Version.cs</Link> </Compile> <Compile Include="Properties\AssemblyInfo.cs" /> - <Compile Include="OAuth2Interceptors.cs" /> + <Compile Include="AuthInterceptors.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <ItemGroup> diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec index 2dc10d24c2..f1f8f7c709 100644 --- a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec +++ b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec @@ -15,7 +15,7 @@ <copyright>Copyright 2015, Google Inc.</copyright> <tags>gRPC RPC Protocol HTTP/2 Auth OAuth2</tags> <dependencies> - <dependency id="Google.Apis.Auth" version="1.9.2" /> + <dependency id="Google.Apis.Auth" version="1.9.3" /> <dependency id="Grpc.Core" version="$version$" /> </dependencies> </metadata> diff --git a/src/csharp/Grpc.Auth/OAuth2Interceptors.cs b/src/csharp/Grpc.Auth/OAuth2Interceptors.cs deleted file mode 100644 index d628a83246..0000000000 --- a/src/csharp/Grpc.Auth/OAuth2Interceptors.cs +++ /dev/null @@ -1,115 +0,0 @@ -#region Copyright notice and license - -// Copyright 2015, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#endregion - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Security.Cryptography.X509Certificates; -using System.Text.RegularExpressions; -using System.Threading; -using System.Threading.Tasks; - -using Google.Apis.Auth.OAuth2; -using Google.Apis.Util; -using Grpc.Core; -using Grpc.Core.Utils; - -namespace Grpc.Auth -{ - public static class OAuth2Interceptors - { - /// <summary> - /// Creates OAuth2 interceptor that will obtain access token from GoogleCredentials. - /// </summary> - public static MetadataInterceptorDelegate FromCredential(GoogleCredential googleCredential) - { - var interceptor = new OAuth2Interceptor(googleCredential, SystemClock.Default); - return new MetadataInterceptorDelegate(interceptor.InterceptHeaders); - } - - /// <summary> - /// Creates OAuth2 interceptor that will use given OAuth2 token. - /// </summary> - /// <param name="oauth2Token"></param> - /// <returns></returns> - public static MetadataInterceptorDelegate FromAccessToken(string oauth2Token) - { - Preconditions.CheckNotNull(oauth2Token); - return new MetadataInterceptorDelegate((authUri, metadata) => - { - metadata.Add(OAuth2Interceptor.CreateBearerTokenHeader(oauth2Token)); - }); - } - - /// <summary> - /// Injects OAuth2 authorization header into initial metadata (= request headers). - /// </summary> - private class OAuth2Interceptor - { - private const string AuthorizationHeader = "Authorization"; - private const string Schema = "Bearer"; - - private ITokenAccess credential; - private IClock clock; - - public OAuth2Interceptor(ITokenAccess credential, IClock clock) - { - this.credential = credential; - this.clock = clock; - } - - /// <summary> - /// Gets access token and requests refreshing it if is going to expire soon. - /// </summary> - /// <param name="cancellationToken"></param> - /// <returns></returns> - public string GetAccessToken(string authUri, CancellationToken cancellationToken) - { - // TODO(jtattermusch): Rethink synchronous wait to obtain the result. - return credential.GetAccessTokenForRequestAsync(authUri, cancellationToken: cancellationToken).GetAwaiter().GetResult(); - } - - public void InterceptHeaders(string authUri, Metadata metadata) - { - var accessToken = GetAccessToken(authUri, CancellationToken.None); - metadata.Add(CreateBearerTokenHeader(accessToken)); - } - - public static Metadata.Entry CreateBearerTokenHeader(string accessToken) - { - return new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken); - } - } - } -} diff --git a/src/csharp/Grpc.Core.Tests/ChannelTest.cs b/src/csharp/Grpc.Core.Tests/ChannelTest.cs index 2787572924..dfbd92879e 100644 --- a/src/csharp/Grpc.Core.Tests/ChannelTest.cs +++ b/src/csharp/Grpc.Core.Tests/ChannelTest.cs @@ -41,12 +41,6 @@ namespace Grpc.Core.Tests { public class ChannelTest { - [TestFixtureTearDown] - public void CleanupClass() - { - GrpcEnvironment.Shutdown(); - } - [Test] public void Constructor_RejectsInvalidParams() { @@ -56,36 +50,33 @@ namespace Grpc.Core.Tests [Test] public void State_IdleAfterCreation() { - using (var channel = new Channel("localhost", Credentials.Insecure)) - { - Assert.AreEqual(ChannelState.Idle, channel.State); - } + var channel = new Channel("localhost", Credentials.Insecure); + Assert.AreEqual(ChannelState.Idle, channel.State); + channel.ShutdownAsync().Wait(); } [Test] public void WaitForStateChangedAsync_InvalidArgument() { - using (var channel = new Channel("localhost", Credentials.Insecure)) - { - Assert.Throws(typeof(ArgumentException), () => channel.WaitForStateChangedAsync(ChannelState.FatalFailure)); - } + var channel = new Channel("localhost", Credentials.Insecure); + Assert.Throws(typeof(ArgumentException), () => channel.WaitForStateChangedAsync(ChannelState.FatalFailure)); + channel.ShutdownAsync().Wait(); } [Test] public void ResolvedTarget() { - using (var channel = new Channel("127.0.0.1", Credentials.Insecure)) - { - Assert.IsTrue(channel.ResolvedTarget.Contains("127.0.0.1")); - } + var channel = new Channel("127.0.0.1", Credentials.Insecure); + Assert.IsTrue(channel.ResolvedTarget.Contains("127.0.0.1")); + channel.ShutdownAsync().Wait(); } [Test] - public void Dispose_IsIdempotent() + public void Shutdown_AllowedOnlyOnce() { var channel = new Channel("localhost", Credentials.Insecure); - channel.Dispose(); - channel.Dispose(); + channel.ShutdownAsync().Wait(); + Assert.Throws(typeof(InvalidOperationException), () => channel.ShutdownAsync().GetAwaiter().GetResult()); } } } diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs index e49fdb5268..68279a2007 100644 --- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs @@ -63,16 +63,10 @@ namespace Grpc.Core.Tests [TearDown] public void Cleanup() { - channel.Dispose(); + channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); } - [TestFixtureTearDown] - public void CleanupClass() - { - GrpcEnvironment.Shutdown(); - } - [Test] public async Task UnaryCall() { @@ -208,13 +202,6 @@ namespace Grpc.Core.Tests } [Test] - public void UnaryCall_DisposedChannel() - { - channel.Dispose(); - Assert.Throws(typeof(ObjectDisposedException), () => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "ABC")); - } - - [Test] public void UnaryCallPerformance() { helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) => diff --git a/src/csharp/Grpc.Core.Tests/CompressionTest.cs b/src/csharp/Grpc.Core.Tests/CompressionTest.cs index 9547683f60..378c81851c 100644 --- a/src/csharp/Grpc.Core.Tests/CompressionTest.cs +++ b/src/csharp/Grpc.Core.Tests/CompressionTest.cs @@ -62,16 +62,10 @@ namespace Grpc.Core.Tests [TearDown] public void Cleanup() { - channel.Dispose(); + channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); } - [TestFixtureTearDown] - public void CleanupClass() - { - GrpcEnvironment.Shutdown(); - } - [Test] public void WriteOptions_Unary() { diff --git a/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs b/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs index db5f953b0e..2db3f286f7 100644 --- a/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs +++ b/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs @@ -62,16 +62,10 @@ namespace Grpc.Core.Tests [TearDown] public void Cleanup() { - channel.Dispose(); + channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); } - [TestFixtureTearDown] - public void CleanupClass() - { - GrpcEnvironment.Shutdown(); - } - [Test] public async Task PropagateCancellation() { diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj index d6a8f52570..ad4e94a695 100644 --- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj +++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj @@ -64,6 +64,7 @@ <Link>Version.cs</Link> </Compile> <Compile Include="ClientBaseTest.cs" /> + <Compile Include="ShutdownTest.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="ClientServerTest.cs" /> <Compile Include="ServerTest.cs" /> @@ -82,6 +83,7 @@ <Compile Include="ResponseHeadersTest.cs" /> <Compile Include="CompressionTest.cs" /> <Compile Include="ContextPropagationTest.cs" /> + <Compile Include="MetadataTest.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <ItemGroup> diff --git a/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs index 4ed93c7eca..4fdfab5a99 100644 --- a/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs +++ b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs @@ -43,34 +43,40 @@ namespace Grpc.Core.Tests [Test] public void InitializeAndShutdownGrpcEnvironment() { - var env = GrpcEnvironment.GetInstance(); + var env = GrpcEnvironment.AddRef(); Assert.IsNotNull(env.CompletionQueue); - GrpcEnvironment.Shutdown(); + GrpcEnvironment.Release(); } [Test] public void SubsequentInvocations() { - var env1 = GrpcEnvironment.GetInstance(); - var env2 = GrpcEnvironment.GetInstance(); + var env1 = GrpcEnvironment.AddRef(); + var env2 = GrpcEnvironment.AddRef(); Assert.IsTrue(object.ReferenceEquals(env1, env2)); - GrpcEnvironment.Shutdown(); - GrpcEnvironment.Shutdown(); + GrpcEnvironment.Release(); + GrpcEnvironment.Release(); } [Test] public void InitializeAfterShutdown() { - var env1 = GrpcEnvironment.GetInstance(); - GrpcEnvironment.Shutdown(); + var env1 = GrpcEnvironment.AddRef(); + GrpcEnvironment.Release(); - var env2 = GrpcEnvironment.GetInstance(); - GrpcEnvironment.Shutdown(); + var env2 = GrpcEnvironment.AddRef(); + GrpcEnvironment.Release(); Assert.IsFalse(object.ReferenceEquals(env1, env2)); } [Test] + public void ReleaseWithoutAddRef() + { + Assert.Throws(typeof(InvalidOperationException), () => GrpcEnvironment.Release()); + } + + [Test] public void GetCoreVersionString() { var coreVersion = GrpcEnvironment.GetCoreVersionString(); diff --git a/src/csharp/Grpc.Core.Tests/MetadataTest.cs b/src/csharp/Grpc.Core.Tests/MetadataTest.cs new file mode 100644 index 0000000000..c00f945d6a --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/MetadataTest.cs @@ -0,0 +1,120 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.Core.Tests +{ + public class MetadataTest + { + [Test] + public void AsciiEntry() + { + var entry = new Metadata.Entry("ABC", "XYZ"); + Assert.IsFalse(entry.IsBinary); + Assert.AreEqual("abc", entry.Key); // key is in lowercase. + Assert.AreEqual("XYZ", entry.Value); + CollectionAssert.AreEqual(new[] { (byte)'X', (byte)'Y', (byte)'Z' }, entry.ValueBytes); + + Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc-bin", "xyz")); + + Assert.AreEqual("[Entry: key=abc, value=XYZ]", entry.ToString()); + } + + [Test] + public void BinaryEntry() + { + var bytes = new byte[] { 1, 2, 3 }; + var entry = new Metadata.Entry("ABC-BIN", bytes); + Assert.IsTrue(entry.IsBinary); + Assert.AreEqual("abc-bin", entry.Key); // key is in lowercase. + Assert.Throws(typeof(InvalidOperationException), () => { var v = entry.Value; }); + CollectionAssert.AreEqual(bytes, entry.ValueBytes); + + Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc", bytes)); + + Assert.AreEqual("[Entry: key=abc-bin, valueBytes=System.Byte[]]", entry.ToString()); + } + + [Test] + public void Entry_ConstructionPreconditions() + { + Assert.Throws(typeof(ArgumentNullException), () => new Metadata.Entry(null, "xyz")); + Assert.Throws(typeof(ArgumentNullException), () => new Metadata.Entry("abc", (string)null)); + Assert.Throws(typeof(ArgumentNullException), () => new Metadata.Entry("abc-bin", (byte[])null)); + } + + [Test] + public void Entry_Immutable() + { + var origBytes = new byte[] { 1, 2, 3 }; + var bytes = new byte[] { 1, 2, 3 }; + var entry = new Metadata.Entry("ABC-BIN", bytes); + bytes[0] = 255; // changing the array passed to constructor should have any effect. + CollectionAssert.AreEqual(origBytes, entry.ValueBytes); + + entry.ValueBytes[0] = 255; + CollectionAssert.AreEqual(origBytes, entry.ValueBytes); + } + + [Test] + public void Entry_CreateUnsafe_Ascii() + { + var bytes = new byte[] { (byte)'X', (byte)'y' }; + var entry = Metadata.Entry.CreateUnsafe("abc", bytes); + Assert.IsFalse(entry.IsBinary); + Assert.AreEqual("abc", entry.Key); + Assert.AreEqual("Xy", entry.Value); + CollectionAssert.AreEqual(bytes, entry.ValueBytes); + } + + [Test] + public void Entry_CreateUnsafe_Binary() + { + var bytes = new byte[] { 1, 2, 3 }; + var entry = Metadata.Entry.CreateUnsafe("abc-bin", bytes); + Assert.IsTrue(entry.IsBinary); + Assert.AreEqual("abc-bin", entry.Key); + Assert.Throws(typeof(InvalidOperationException), () => { var v = entry.Value; }); + CollectionAssert.AreEqual(bytes, entry.ValueBytes); + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs b/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs index 981b8ea3c8..706006702e 100644 --- a/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs +++ b/src/csharp/Grpc.Core.Tests/ResponseHeadersTest.cs @@ -69,16 +69,10 @@ namespace Grpc.Core.Tests [TearDown] public void Cleanup() { - channel.Dispose(); + channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); } - [TestFixtureTearDown] - public void CleanupClass() - { - GrpcEnvironment.Shutdown(); - } - [Test] public void WriteResponseHeaders_NullNotAllowed() { diff --git a/src/csharp/Grpc.Core.Tests/ServerTest.cs b/src/csharp/Grpc.Core.Tests/ServerTest.cs index 485006ebac..e7193c843b 100644 --- a/src/csharp/Grpc.Core.Tests/ServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/ServerTest.cs @@ -51,7 +51,6 @@ namespace Grpc.Core.Tests }; server.Start(); server.ShutdownAsync().Wait(); - GrpcEnvironment.Shutdown(); } [Test] @@ -67,8 +66,7 @@ namespace Grpc.Core.Tests Assert.Greater(boundPort.BoundPort, 0); server.Start(); - server.ShutdownAsync(); - GrpcEnvironment.Shutdown(); + server.ShutdownAsync().Wait(); } [Test] @@ -83,7 +81,6 @@ namespace Grpc.Core.Tests Assert.Throws(typeof(InvalidOperationException), () => server.Services.Add(ServerServiceDefinition.CreateBuilder("serviceName").Build())); server.ShutdownAsync().Wait(); - GrpcEnvironment.Shutdown(); } } } diff --git a/src/csharp/Grpc.Core.Tests/ShutdownTest.cs b/src/csharp/Grpc.Core.Tests/ShutdownTest.cs new file mode 100644 index 0000000000..a2be7ddd5e --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/ShutdownTest.cs @@ -0,0 +1,77 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.Core.Tests +{ + public class ShutdownTest + { + const string Host = "127.0.0.1"; + + MockServiceHelper helper; + Server server; + Channel channel; + + [SetUp] + public void Init() + { + helper = new MockServiceHelper(Host); + server = helper.GetServer(); + server.Start(); + channel = helper.GetChannel(); + } + + [Test] + public async Task AbandonedCall() + { + helper.DuplexStreamingHandler = new DuplexStreamingServerMethod<string, string>(async (requestStream, responseStream, context) => + { + await requestStream.ToListAsync(); + }); + + var call = Calls.AsyncDuplexStreamingCall(helper.CreateDuplexStreamingCall(new CallOptions(deadline: DateTime.UtcNow.AddMilliseconds(1)))); + + channel.ShutdownAsync().Wait(); + server.ShutdownAsync().Wait(); + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs index d875d601b9..41f661f62d 100644 --- a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs +++ b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs @@ -65,16 +65,10 @@ namespace Grpc.Core.Tests [TearDown] public void Cleanup() { - channel.Dispose(); + channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); } - [TestFixtureTearDown] - public void CleanupClass() - { - GrpcEnvironment.Shutdown(); - } - [Test] public void InfiniteDeadline() { diff --git a/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs b/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs index bf020cd627..fb9b562c77 100644 --- a/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs +++ b/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs @@ -89,6 +89,24 @@ namespace Grpc.Core } /// <summary> + /// Gets the call status if the call has already finished. + /// Throws InvalidOperationException otherwise. + /// </summary> + public Status GetStatus() + { + return getStatusFunc(); + } + + /// <summary> + /// Gets the call trailing metadata if the call has already finished. + /// Throws InvalidOperationException otherwise. + /// </summary> + public Metadata GetTrailers() + { + return getTrailersFunc(); + } + + /// <summary> /// Provides means to cleanup after the call. /// If the call has already finished normally (request stream has been completed and call result has been received), doesn't do anything. /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call. diff --git a/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs b/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs index 0979de606f..183c84216a 100644 --- a/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs +++ b/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs @@ -32,8 +32,6 @@ #endregion using System; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; namespace Grpc.Core { diff --git a/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs b/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs index 380efcdb0e..ab2049f269 100644 --- a/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs +++ b/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs @@ -32,8 +32,6 @@ #endregion using System; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; namespace Grpc.Core { diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs index 64c6adf2bf..2f8519dfa3 100644 --- a/src/csharp/Grpc.Core/Channel.cs +++ b/src/csharp/Grpc.Core/Channel.cs @@ -45,14 +45,19 @@ namespace Grpc.Core /// <summary> /// gRPC Channel /// </summary> - public class Channel : IDisposable + public class Channel { static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<Channel>(); + readonly object myLock = new object(); + readonly AtomicCounter activeCallCounter = new AtomicCounter(); + readonly string target; readonly GrpcEnvironment environment; readonly ChannelSafeHandle handle; readonly List<ChannelOption> options; + + bool shutdownRequested; bool disposed; /// <summary> @@ -65,7 +70,7 @@ namespace Grpc.Core public Channel(string target, Credentials credentials, IEnumerable<ChannelOption> options = null) { this.target = Preconditions.CheckNotNull(target, "target"); - this.environment = GrpcEnvironment.GetInstance(); + this.environment = GrpcEnvironment.AddRef(); this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>(); EnsureUserAgentChannelOption(this.options); @@ -172,12 +177,26 @@ namespace Grpc.Core } /// <summary> - /// Destroys the underlying channel. + /// Waits until there are no more active calls for this channel and then cleans up + /// resources used by this channel. /// </summary> - public void Dispose() + public async Task ShutdownAsync() { - Dispose(true); - GC.SuppressFinalize(this); + lock (myLock) + { + Preconditions.CheckState(!shutdownRequested); + shutdownRequested = true; + } + + var activeCallCount = activeCallCounter.Count; + if (activeCallCount > 0) + { + Logger.Warning("Channel shutdown was called but there are still {0} active calls for that channel.", activeCallCount); + } + + handle.Dispose(); + + await Task.Run(() => GrpcEnvironment.Release()); } internal ChannelSafeHandle Handle @@ -196,13 +215,20 @@ namespace Grpc.Core } } - protected virtual void Dispose(bool disposing) + internal void AddCallReference(object call) { - if (disposing && handle != null && !disposed) - { - disposed = true; - handle.Dispose(); - } + activeCallCounter.Increment(); + + bool success = false; + handle.DangerousAddRef(ref success); + Preconditions.CheckState(success); + } + + internal void RemoveCallReference(object call) + { + handle.DangerousRelease(); + + activeCallCounter.Decrement(); } private static void EnsureUserAgentChannelOption(List<ChannelOption> options) diff --git a/src/csharp/Grpc.Core/ChannelOptions.cs b/src/csharp/Grpc.Core/ChannelOptions.cs index 0cb2953f2c..ad54b46ad5 100644 --- a/src/csharp/Grpc.Core/ChannelOptions.cs +++ b/src/csharp/Grpc.Core/ChannelOptions.cs @@ -71,7 +71,7 @@ namespace Grpc.Core /// Creates a channel option with an integer value. /// </summary> /// <param name="name">Name.</param> - /// <param name="stringValue">String value.</param> + /// <param name="intValue">Integer value.</param> public ChannelOption(string name, int intValue) { this.type = OptionType.Integer; diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs index f240d777b9..903449439b 100644 --- a/src/csharp/Grpc.Core/ClientBase.cs +++ b/src/csharp/Grpc.Core/ClientBase.cs @@ -32,15 +32,15 @@ #endregion using System; -using System.Collections.Generic; using System.Text.RegularExpressions; - -using Grpc.Core.Internal; -using Grpc.Core.Utils; +using System.Threading.Tasks; namespace Grpc.Core { - public delegate void MetadataInterceptorDelegate(string authUri, Metadata metadata); + /// <summary> + /// Interceptor for call headers. + /// </summary> + public delegate void HeaderInterceptor(IMethod method, string authUri, Metadata metadata); /// <summary> /// Base class for client-side stubs. @@ -60,10 +60,10 @@ namespace Grpc.Core } /// <summary> - /// Can be used to register a custom header (initial metadata) interceptor. - /// The delegate each time before a new call on this client is started. + /// Can be used to register a custom header (request metadata) interceptor. + /// The interceptor is invoked each time a new call on this client is started. /// </summary> - public MetadataInterceptorDelegate HeaderInterceptor + public HeaderInterceptor HeaderInterceptor { get; set; @@ -107,7 +107,7 @@ namespace Grpc.Core options = options.WithHeaders(new Metadata()); } var authUri = authUriBase != null ? authUriBase + method.ServiceName : null; - interceptor(authUri, options.Headers); + interceptor(method, authUri, options.Headers); } return new CallInvocationDetails<TRequest, TResponse>(channel, method, Host, options); } @@ -119,7 +119,8 @@ namespace Grpc.Core internal static string GetAuthUriBase(string target) { var match = ChannelTargetPattern.Match(target); - if (!match.Success) { + if (!match.Success) + { return null; } return "https://" + match.Groups[2].Value + "/"; diff --git a/src/csharp/Grpc.Core/ContextPropagationToken.cs b/src/csharp/Grpc.Core/ContextPropagationToken.cs index 2e4bfc9e47..a5bf1b5a70 100644 --- a/src/csharp/Grpc.Core/ContextPropagationToken.cs +++ b/src/csharp/Grpc.Core/ContextPropagationToken.cs @@ -132,7 +132,6 @@ namespace Grpc.Core bool propagateDeadline; bool propagateCancellation; - /// <summary> /// Creates new context propagation options. /// </summary> diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs index 30d8c80235..0a44eead74 100644 --- a/src/csharp/Grpc.Core/GrpcEnvironment.cs +++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs @@ -58,6 +58,7 @@ namespace Grpc.Core static object staticLock = new object(); static GrpcEnvironment instance; + static int refCount; static ILogger logger = new ConsoleLogger(); @@ -67,13 +68,14 @@ namespace Grpc.Core bool isClosed; /// <summary> - /// Returns an instance of initialized gRPC environment. - /// Subsequent invocations return the same instance unless Shutdown has been called first. + /// Returns a reference-counted instance of initialized gRPC environment. + /// Subsequent invocations return the same instance unless reference count has dropped to zero previously. /// </summary> - internal static GrpcEnvironment GetInstance() + internal static GrpcEnvironment AddRef() { lock (staticLock) { + refCount++; if (instance == null) { instance = new GrpcEnvironment(); @@ -83,14 +85,16 @@ namespace Grpc.Core } /// <summary> - /// Shuts down the gRPC environment if it was initialized before. - /// Blocks until the environment has been fully shutdown. + /// Decrements the reference count for currently active environment and shuts down the gRPC environment if reference count drops to zero. + /// (and blocks until the environment has been fully shutdown). /// </summary> - public static void Shutdown() + internal static void Release() { lock (staticLock) { - if (instance != null) + Preconditions.CheckState(refCount > 0); + refCount--; + if (refCount == 0) { instance.Close(); instance = null; @@ -125,12 +129,10 @@ namespace Grpc.Core private GrpcEnvironment() { NativeLogRedirector.Redirect(); - grpcsharp_init(); + GrpcNativeInit(); completionRegistry = new CompletionRegistry(this); threadPool = new GrpcThreadPool(this, THREAD_POOL_SIZE); threadPool.Start(); - // TODO: use proper logging here - Logger.Info("gRPC initialized."); } /// <summary> @@ -175,6 +177,17 @@ namespace Grpc.Core return Marshal.PtrToStringAnsi(ptr); } + + internal static void GrpcNativeInit() + { + grpcsharp_init(); + } + + internal static void GrpcNativeShutdown() + { + grpcsharp_shutdown(); + } + /// <summary> /// Shuts down this environment. /// </summary> @@ -185,12 +198,10 @@ namespace Grpc.Core throw new InvalidOperationException("Close has already been called"); } threadPool.Stop(); - grpcsharp_shutdown(); + GrpcNativeShutdown(); isClosed = true; debugStats.CheckOK(); - - Logger.Info("gRPC shutdown."); } } } diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index 2c3e3d75ea..bb9ba5b8dd 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -311,9 +311,9 @@ namespace Grpc.Core.Internal } } - protected override void OnReleaseResources() + protected override void OnAfterReleaseResources() { - details.Channel.Environment.DebugStats.ActiveClientCalls.Decrement(); + details.Channel.RemoveCallReference(this); } private void Initialize(CompletionQueueSafeHandle cq) @@ -323,7 +323,9 @@ namespace Grpc.Core.Internal var call = details.Channel.Handle.CreateCall(details.Channel.Environment.CompletionRegistry, parentCall, ContextPropagationToken.DefaultMask, cq, details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value)); - details.Channel.Environment.DebugStats.ActiveClientCalls.Increment(); + + details.Channel.AddCallReference(this); + InitializeInternal(call); RegisterCancellationCallback(); } diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs index 6ca4bbdafc..1808294f43 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs @@ -189,15 +189,15 @@ namespace Grpc.Core.Internal private void ReleaseResources() { - OnReleaseResources(); if (call != null) { call.Dispose(); } disposed = true; + OnAfterReleaseResources(); } - protected virtual void OnReleaseResources() + protected virtual void OnAfterReleaseResources() { } @@ -212,7 +212,7 @@ namespace Grpc.Core.Internal Preconditions.CheckState(sendCompletionDelegate == null, "Only one write can be pending at a time"); } - protected void CheckReadingAllowed() + protected virtual void CheckReadingAllowed() { Preconditions.CheckState(started); Preconditions.CheckState(!disposed); diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs index 3710a65d6b..6278c0191e 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs @@ -50,16 +50,19 @@ namespace Grpc.Core.Internal readonly TaskCompletionSource<object> finishedServersideTcs = new TaskCompletionSource<object>(); readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); readonly GrpcEnvironment environment; + readonly Server server; - public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer, GrpcEnvironment environment) : base(serializer, deserializer) + public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer, GrpcEnvironment environment, Server server) : base(serializer, deserializer) { this.environment = Preconditions.CheckNotNull(environment); + this.server = Preconditions.CheckNotNull(server); } public void Initialize(CallSafeHandle call) { call.SetCompletionRegistry(environment.CompletionRegistry); - environment.DebugStats.ActiveServerCalls.Increment(); + + server.AddCallReference(this); InitializeInternal(call); } @@ -168,9 +171,15 @@ namespace Grpc.Core.Internal } } - protected override void OnReleaseResources() + protected override void CheckReadingAllowed() + { + base.CheckReadingAllowed(); + Preconditions.CheckArgument(!cancelRequested); + } + + protected override void OnAfterReleaseResources() { - environment.DebugStats.ActiveServerCalls.Decrement(); + server.RemoveCallReference(this); } /// <summary> diff --git a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs index 6a2add54db..3a96414bea 100644 --- a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs @@ -134,7 +134,7 @@ namespace Grpc.Core.Internal } // Gets data of server_rpc_new completion. - public ServerRpcNew GetServerRpcNew() + public ServerRpcNew GetServerRpcNew(Server server) { var call = grpcsharp_batch_context_server_rpc_new_call(this); @@ -145,7 +145,7 @@ namespace Grpc.Core.Internal IntPtr metadataArrayPtr = grpcsharp_batch_context_server_rpc_new_request_metadata(this); var metadata = MetadataArraySafeHandle.ReadMetadataFromPtrUnsafe(metadataArrayPtr); - return new ServerRpcNew(call, method, host, deadline, metadata); + return new ServerRpcNew(server, call, method, host, deadline, metadata); } // Gets data of receive_close_on_server completion. @@ -198,14 +198,16 @@ namespace Grpc.Core.Internal /// </summary> internal struct ServerRpcNew { + readonly Server server; readonly CallSafeHandle call; readonly string method; readonly string host; readonly Timespec deadline; readonly Metadata requestMetadata; - public ServerRpcNew(CallSafeHandle call, string method, string host, Timespec deadline, Metadata requestMetadata) + public ServerRpcNew(Server server, CallSafeHandle call, string method, string host, Timespec deadline, Metadata requestMetadata) { + this.server = server; this.call = call; this.method = method; this.host = host; @@ -213,6 +215,14 @@ namespace Grpc.Core.Internal this.requestMetadata = requestMetadata; } + public Server Server + { + get + { + return this.server; + } + } + public CallSafeHandle Call { get diff --git a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs index 7f03bf4ea5..8cef566c14 100644 --- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs @@ -68,11 +68,17 @@ namespace Grpc.Core.Internal public static ChannelSafeHandle CreateInsecure(string target, ChannelArgsSafeHandle channelArgs) { + // Increment reference count for the native gRPC environment to make sure we don't do grpc_shutdown() before destroying the server handle. + // Doing so would make object finalizer crash if we end up abandoning the handle. + GrpcEnvironment.GrpcNativeInit(); return grpcsharp_insecure_channel_create(target, channelArgs); } public static ChannelSafeHandle CreateSecure(CredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs) { + // Increment reference count for the native gRPC environment to make sure we don't do grpc_shutdown() before destroying the server handle. + // Doing so would make object finalizer crash if we end up abandoning the handle. + GrpcEnvironment.GrpcNativeInit(); return grpcsharp_secure_channel_create(credentials, target, channelArgs); } @@ -107,6 +113,7 @@ namespace Grpc.Core.Internal protected override bool ReleaseHandle() { grpcsharp_channel_destroy(handle); + GrpcEnvironment.GrpcNativeShutdown(); return true; } } diff --git a/src/csharp/Grpc.Core/Internal/DebugStats.cs b/src/csharp/Grpc.Core/Internal/DebugStats.cs index 8793450ff3..1bea1adf9e 100644 --- a/src/csharp/Grpc.Core/Internal/DebugStats.cs +++ b/src/csharp/Grpc.Core/Internal/DebugStats.cs @@ -38,10 +38,6 @@ namespace Grpc.Core.Internal { internal class DebugStats { - public readonly AtomicCounter ActiveClientCalls = new AtomicCounter(); - - public readonly AtomicCounter ActiveServerCalls = new AtomicCounter(); - public readonly AtomicCounter PendingBatchCompletions = new AtomicCounter(); /// <summary> @@ -49,16 +45,6 @@ namespace Grpc.Core.Internal /// </summary> public void CheckOK() { - var remainingClientCalls = ActiveClientCalls.Count; - if (remainingClientCalls != 0) - { - DebugWarning(string.Format("Detected {0} client calls that weren't disposed properly.", remainingClientCalls)); - } - var remainingServerCalls = ActiveServerCalls.Count; - if (remainingServerCalls != 0) - { - DebugWarning(string.Format("Detected {0} server calls that weren't disposed properly.", remainingServerCalls)); - } var pendingBatchCompletions = PendingBatchCompletions.Count; if (pendingBatchCompletions != 0) { diff --git a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs index cb4c7c821e..4b7124ee74 100644 --- a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs +++ b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs @@ -83,8 +83,6 @@ namespace Grpc.Core.Internal lock (myLock) { cq.Shutdown(); - - Logger.Info("Waiting for GRPC threads to finish."); foreach (var thread in threads) { thread.Join(); @@ -136,7 +134,6 @@ namespace Grpc.Core.Internal } } while (ev.type != GRPCCompletionType.Shutdown); - Logger.Info("Completion queue has shutdown successfully, thread {0} exiting.", Thread.CurrentThread.Name); } } } diff --git a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs index 427c16fac6..83994f6762 100644 --- a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs @@ -70,7 +70,8 @@ namespace Grpc.Core.Internal var metadataArray = grpcsharp_metadata_array_create(new UIntPtr((ulong)metadata.Count)); for (int i = 0; i < metadata.Count; i++) { - grpcsharp_metadata_array_add(metadataArray, metadata[i].Key, metadata[i].ValueBytes, new UIntPtr((ulong)metadata[i].ValueBytes.Length)); + var valueBytes = metadata[i].GetSerializedValueUnsafe(); + grpcsharp_metadata_array_add(metadataArray, metadata[i].Key, valueBytes, new UIntPtr((ulong)valueBytes.Length)); } return metadataArray; } @@ -94,7 +95,7 @@ namespace Grpc.Core.Internal string key = Marshal.PtrToStringAnsi(grpcsharp_metadata_array_get_key(metadataArray, index)); var bytes = new byte[grpcsharp_metadata_array_get_value_length(metadataArray, index).ToUInt64()]; Marshal.Copy(grpcsharp_metadata_array_get_value(metadataArray, index), bytes, 0, bytes.Length); - metadata.Add(new Metadata.Entry(key, bytes)); + metadata.Add(Metadata.Entry.CreateUnsafe(key, bytes)); } return metadata; } diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs index 688f9f6fec..59f4c5727c 100644 --- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs +++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs @@ -67,7 +67,7 @@ namespace Grpc.Core.Internal var asyncCall = new AsyncCallServer<TRequest, TResponse>( method.ResponseMarshaller.Serializer, method.RequestMarshaller.Deserializer, - environment); + environment, newRpc.Server); asyncCall.Initialize(newRpc.Call); var finishedTask = asyncCall.ServerSideCallAsync(); @@ -123,7 +123,7 @@ namespace Grpc.Core.Internal var asyncCall = new AsyncCallServer<TRequest, TResponse>( method.ResponseMarshaller.Serializer, method.RequestMarshaller.Deserializer, - environment); + environment, newRpc.Server); asyncCall.Initialize(newRpc.Call); var finishedTask = asyncCall.ServerSideCallAsync(); @@ -179,7 +179,7 @@ namespace Grpc.Core.Internal var asyncCall = new AsyncCallServer<TRequest, TResponse>( method.ResponseMarshaller.Serializer, method.RequestMarshaller.Deserializer, - environment); + environment, newRpc.Server); asyncCall.Initialize(newRpc.Call); var finishedTask = asyncCall.ServerSideCallAsync(); @@ -239,7 +239,7 @@ namespace Grpc.Core.Internal var asyncCall = new AsyncCallServer<TRequest, TResponse>( method.ResponseMarshaller.Serializer, method.RequestMarshaller.Deserializer, - environment); + environment, newRpc.Server); asyncCall.Initialize(newRpc.Call); var finishedTask = asyncCall.ServerSideCallAsync(); @@ -278,7 +278,7 @@ namespace Grpc.Core.Internal { // We don't care about the payload type here. var asyncCall = new AsyncCallServer<byte[], byte[]>( - (payload) => payload, (payload) => payload, environment); + (payload) => payload, (payload) => payload, environment, newRpc.Server); asyncCall.Initialize(newRpc.Call); var finishedTask = asyncCall.ServerSideCallAsync(); diff --git a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs index f9b44b1acf..5ee7ac14e8 100644 --- a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs @@ -74,6 +74,9 @@ namespace Grpc.Core.Internal public static ServerSafeHandle NewServer(CompletionQueueSafeHandle cq, ChannelArgsSafeHandle args) { + // Increment reference count for the native gRPC environment to make sure we don't do grpc_shutdown() before destroying the server handle. + // Doing so would make object finalizer crash if we end up abandoning the handle. + GrpcEnvironment.GrpcNativeInit(); return grpcsharp_server_create(cq, args); } @@ -109,6 +112,7 @@ namespace Grpc.Core.Internal protected override bool ReleaseHandle() { grpcsharp_server_destroy(handle); + GrpcEnvironment.GrpcNativeShutdown(); return true; } diff --git a/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs index 382481d871..35561d25d8 100644 --- a/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs +++ b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs @@ -51,7 +51,19 @@ namespace Grpc.Core.Logging private ConsoleLogger(Type forType) { this.forType = forType; - this.forTypeString = forType != null ? forType.FullName + " " : ""; + if (forType != null) + { + var namespaceStr = forType.Namespace ?? ""; + if (namespaceStr.Length > 0) + { + namespaceStr += "."; + } + this.forTypeString = namespaceStr + forType.Name + " "; + } + else + { + this.forTypeString = ""; + } } /// <summary> diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs index 9db2abf46e..a589b50caa 100644 --- a/src/csharp/Grpc.Core/Metadata.cs +++ b/src/csharp/Grpc.Core/Metadata.cs @@ -46,6 +46,11 @@ namespace Grpc.Core public sealed class Metadata : IList<Metadata.Entry> { /// <summary> + /// All binary headers should have this suffix. + /// </summary> + public const string BinaryHeaderSuffix = "-bin"; + + /// <summary> /// An read-only instance of metadata containing no entries. /// </summary> public static readonly Metadata Empty = new Metadata().Freeze(); @@ -181,23 +186,49 @@ namespace Grpc.Core private static readonly Encoding Encoding = Encoding.ASCII; readonly string key; - string value; - byte[] valueBytes; + readonly string value; + readonly byte[] valueBytes; + + private Entry(string key, string value, byte[] valueBytes) + { + this.key = key; + this.value = value; + this.valueBytes = valueBytes; + } + /// <summary> + /// Initializes a new instance of the <see cref="Grpc.Core.Metadata+Entry"/> struct with a binary value. + /// </summary> + /// <param name="key">Metadata key, needs to have suffix indicating a binary valued metadata entry.</param> + /// <param name="valueBytes">Value bytes.</param> public Entry(string key, byte[] valueBytes) { - this.key = Preconditions.CheckNotNull(key, "key"); + this.key = NormalizeKey(key); + Preconditions.CheckArgument(this.key.EndsWith(BinaryHeaderSuffix), + "Key for binary valued metadata entry needs to have suffix indicating binary value."); this.value = null; - this.valueBytes = Preconditions.CheckNotNull(valueBytes, "valueBytes"); + Preconditions.CheckNotNull(valueBytes, "valueBytes"); + this.valueBytes = new byte[valueBytes.Length]; + Buffer.BlockCopy(valueBytes, 0, this.valueBytes, 0, valueBytes.Length); // defensive copy to guarantee immutability } + /// <summary> + /// Initializes a new instance of the <see cref="Grpc.Core.Metadata+Entry"/> struct holding an ASCII value. + /// </summary> + /// <param name="key">Metadata key, must not use suffix indicating a binary valued metadata entry.</param> + /// <param name="value">Value string. Only ASCII characters are allowed.</param> public Entry(string key, string value) { - this.key = Preconditions.CheckNotNull(key, "key"); + this.key = NormalizeKey(key); + Preconditions.CheckArgument(!this.key.EndsWith(BinaryHeaderSuffix), + "Key for ASCII valued metadata entry cannot have suffix indicating binary value."); this.value = Preconditions.CheckNotNull(value, "value"); this.valueBytes = null; } + /// <summary> + /// Gets the metadata entry key. + /// </summary> public string Key { get @@ -206,33 +237,86 @@ namespace Grpc.Core } } + /// <summary> + /// Gets the binary value of this metadata entry. + /// </summary> public byte[] ValueBytes { get { if (valueBytes == null) { - valueBytes = Encoding.GetBytes(value); + return Encoding.GetBytes(value); } - return valueBytes; + + // defensive copy to guarantee immutability + var bytes = new byte[valueBytes.Length]; + Buffer.BlockCopy(valueBytes, 0, bytes, 0, valueBytes.Length); + return bytes; } } + /// <summary> + /// Gets the string value of this metadata entry. + /// </summary> public string Value { get { - if (value == null) - { - value = Encoding.GetString(valueBytes); - } - return value; + Preconditions.CheckState(!IsBinary, "Cannot access string value of a binary metadata entry"); + return value ?? Encoding.GetString(valueBytes); } } - + + /// <summary> + /// Returns <c>true</c> if this entry is a binary-value entry. + /// </summary> + public bool IsBinary + { + get + { + return value == null; + } + } + + /// <summary> + /// Returns a <see cref="System.String"/> that represents the current <see cref="Grpc.Core.Metadata+Entry"/>. + /// </summary> public override string ToString() { - return string.Format("[Entry: key={0}, value={1}]", Key, Value); + if (IsBinary) + { + return string.Format("[Entry: key={0}, valueBytes={1}]", key, valueBytes); + } + + return string.Format("[Entry: key={0}, value={1}]", key, value); + } + + /// <summary> + /// Gets the serialized value for this entry. For binary metadata entries, this leaks + /// the internal <c>valueBytes</c> byte array and caller must not change contents of it. + /// </summary> + internal byte[] GetSerializedValueUnsafe() + { + return valueBytes ?? Encoding.GetBytes(value); + } + + /// <summary> + /// Creates a binary value or ascii value metadata entry from data received from the native layer. + /// We trust C core to give us well-formed data, so we don't perform any checks or defensive copying. + /// </summary> + internal static Entry CreateUnsafe(string key, byte[] valueBytes) + { + if (key.EndsWith(BinaryHeaderSuffix)) + { + return new Entry(key, null, valueBytes); + } + return new Entry(key, Encoding.GetString(valueBytes), null); + } + + private static string NormalizeKey(string key) + { + return Preconditions.CheckNotNull(key, "key").ToLower(); } } } diff --git a/src/csharp/Grpc.Core/Method.cs b/src/csharp/Grpc.Core/Method.cs index 4c208b4a26..4c53285893 100644 --- a/src/csharp/Grpc.Core/Method.cs +++ b/src/csharp/Grpc.Core/Method.cs @@ -55,9 +55,36 @@ namespace Grpc.Core } /// <summary> + /// A non-generic representation of a remote method. + /// </summary> + public interface IMethod + { + /// <summary> + /// Gets the type of the method. + /// </summary> + MethodType Type { get; } + + /// <summary> + /// Gets the name of the service to which this method belongs. + /// </summary> + string ServiceName { get; } + + /// <summary> + /// Gets the unqualified name of the method. + /// </summary> + string Name { get; } + + /// <summary> + /// Gets the fully qualified name of the method. On the server side, methods are dispatched + /// based on this name. + /// </summary> + string FullName { get; } + } + + /// <summary> /// A description of a remote method. /// </summary> - public class Method<TRequest, TResponse> + public class Method<TRequest, TResponse> : IMethod { readonly MethodType type; readonly string serviceName; diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs index c76f126026..28f1686e20 100644 --- a/src/csharp/Grpc.Core/Server.cs +++ b/src/csharp/Grpc.Core/Server.cs @@ -50,6 +50,8 @@ namespace Grpc.Core { static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<Server>(); + readonly AtomicCounter activeCallCounter = new AtomicCounter(); + readonly ServiceDefinitionCollection serviceDefinitions; readonly ServerPortCollection ports; readonly GrpcEnvironment environment; @@ -73,7 +75,7 @@ namespace Grpc.Core { this.serviceDefinitions = new ServiceDefinitionCollection(this); this.ports = new ServerPortCollection(this); - this.environment = GrpcEnvironment.GetInstance(); + this.environment = GrpcEnvironment.AddRef(); this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>(); using (var channelArgs = ChannelOptions.CreateChannelArgs(this.options)) { @@ -106,6 +108,17 @@ namespace Grpc.Core } /// <summary> + /// To allow awaiting termination of the server. + /// </summary> + public Task ShutdownTask + { + get + { + return shutdownTcs.Task; + } + } + + /// <summary> /// Starts the server. /// </summary> public void Start() @@ -136,18 +149,9 @@ namespace Grpc.Core handle.ShutdownAndNotify(HandleServerShutdown, environment); await shutdownTcs.Task; - handle.Dispose(); - } + DisposeHandle(); - /// <summary> - /// To allow awaiting termination of the server. - /// </summary> - public Task ShutdownTask - { - get - { - return shutdownTcs.Task; - } + await Task.Run(() => GrpcEnvironment.Release()); } /// <summary> @@ -166,7 +170,22 @@ namespace Grpc.Core handle.ShutdownAndNotify(HandleServerShutdown, environment); handle.CancelAllCalls(); await shutdownTcs.Task; - handle.Dispose(); + DisposeHandle(); + } + + internal void AddCallReference(object call) + { + activeCallCounter.Increment(); + + bool success = false; + handle.DangerousAddRef(ref success); + Preconditions.CheckState(success); + } + + internal void RemoveCallReference(object call) + { + handle.DangerousRelease(); + activeCallCounter.Decrement(); } /// <summary> @@ -227,6 +246,16 @@ namespace Grpc.Core } } + private void DisposeHandle() + { + var activeCallCount = activeCallCounter.Count; + if (activeCallCount > 0) + { + Logger.Warning("Server shutdown has finished but there are still {0} active calls for that server.", activeCallCount); + } + handle.Dispose(); + } + /// <summary> /// Selects corresponding handler for given call and handles the call. /// </summary> @@ -254,7 +283,7 @@ namespace Grpc.Core { if (success) { - ServerRpcNew newRpc = ctx.GetServerRpcNew(); + ServerRpcNew newRpc = ctx.GetServerRpcNew(this); // after server shutdown, the callback returns with null call if (!newRpc.Call.IsInvalid) diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs index f9839d99f1..abd95cb905 100644 --- a/src/csharp/Grpc.Examples.MathClient/MathClient.cs +++ b/src/csharp/Grpc.Examples.MathClient/MathClient.cs @@ -39,23 +39,21 @@ namespace math { public static void Main(string[] args) { - using (Channel channel = new Channel("127.0.0.1", 23456, Credentials.Insecure)) - { - Math.IMathClient client = new Math.MathClient(channel); - MathExamples.DivExample(client); + var channel = new Channel("127.0.0.1", 23456, Credentials.Insecure); + Math.IMathClient client = new Math.MathClient(channel); + MathExamples.DivExample(client); - MathExamples.DivAsyncExample(client).Wait(); + MathExamples.DivAsyncExample(client).Wait(); - MathExamples.FibExample(client).Wait(); + MathExamples.FibExample(client).Wait(); - MathExamples.SumExample(client).Wait(); + MathExamples.SumExample(client).Wait(); - MathExamples.DivManyExample(client).Wait(); + MathExamples.DivManyExample(client).Wait(); - MathExamples.DependendRequestsExample(client).Wait(); - } + MathExamples.DependendRequestsExample(client).Wait(); - GrpcEnvironment.Shutdown(); + channel.ShutdownAsync().Wait(); } } } diff --git a/src/csharp/Grpc.Examples.MathServer/MathServer.cs b/src/csharp/Grpc.Examples.MathServer/MathServer.cs index 5f7e717b0c..26bef646ec 100644 --- a/src/csharp/Grpc.Examples.MathServer/MathServer.cs +++ b/src/csharp/Grpc.Examples.MathServer/MathServer.cs @@ -56,7 +56,6 @@ namespace math Console.ReadKey(); server.ShutdownAsync().Wait(); - GrpcEnvironment.Shutdown(); } } } diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs index fdef950f09..36c1c947bd 100644 --- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs +++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs @@ -68,9 +68,8 @@ namespace math.Tests [TestFixtureTearDown] public void Cleanup() { - channel.Dispose(); + channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); - GrpcEnvironment.Shutdown(); } [Test] diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs index 024377e216..80c35fb197 100644 --- a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs +++ b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs @@ -71,10 +71,9 @@ namespace Grpc.HealthCheck.Tests [TestFixtureTearDown] public void Cleanup() { - channel.Dispose(); + channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); - GrpcEnvironment.Shutdown(); } [Test] diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index 385ca92086..24c22273fb 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -37,13 +37,15 @@ using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using Google.Apis.Auth.OAuth2; using Google.ProtocolBuffers; + using grpc.testing; using Grpc.Auth; using Grpc.Core; using Grpc.Core.Utils; + using NUnit.Framework; -using Google.Apis.Auth.OAuth2; namespace Grpc.IntegrationTesting { @@ -118,12 +120,10 @@ namespace Grpc.IntegrationTesting }; } - using (Channel channel = new Channel(options.serverHost, options.serverPort.Value, credentials, channelOptions)) - { - TestService.TestServiceClient client = new TestService.TestServiceClient(channel); - await RunTestCaseAsync(options.testCase, client); - } - GrpcEnvironment.Shutdown(); + var channel = new Channel(options.serverHost, options.serverPort.Value, credentials, channelOptions); + TestService.TestServiceClient client = new TestService.TestServiceClient(channel); + await RunTestCaseAsync(options.testCase, client); + channel.ShutdownAsync().Wait(); } private async Task RunTestCaseAsync(string testCase, TestService.TestServiceClient client) @@ -169,6 +169,9 @@ namespace Grpc.IntegrationTesting case "cancel_after_first_response": await RunCancelAfterFirstResponseAsync(client); break; + case "timeout_on_sleeping_server": + await RunTimeoutOnSleepingServerAsync(client); + break; case "benchmark_empty_unary": RunBenchmarkEmptyUnary(client); break; @@ -308,7 +311,7 @@ namespace Grpc.IntegrationTesting Console.WriteLine("running service_account_creds"); var credential = await GoogleCredential.GetApplicationDefaultAsync(); credential = credential.CreateScoped(new[] { AuthScope }); - client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential); + client.HeaderInterceptor = AuthInterceptors.FromCredential(credential); var request = SimpleRequest.CreateBuilder() .SetResponseType(PayloadType.COMPRESSABLE) @@ -332,7 +335,7 @@ namespace Grpc.IntegrationTesting Console.WriteLine("running compute_engine_creds"); var credential = await GoogleCredential.GetApplicationDefaultAsync(); Assert.IsFalse(credential.IsCreateScopedRequired); - client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential); + client.HeaderInterceptor = AuthInterceptors.FromCredential(credential); var request = SimpleRequest.CreateBuilder() .SetResponseType(PayloadType.COMPRESSABLE) @@ -357,7 +360,7 @@ namespace Grpc.IntegrationTesting var credential = await GoogleCredential.GetApplicationDefaultAsync(); // check this a credential with scope support, but don't add the scope. Assert.IsTrue(credential.IsCreateScopedRequired); - client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential); + client.HeaderInterceptor = AuthInterceptors.FromCredential(credential); var request = SimpleRequest.CreateBuilder() .SetResponseType(PayloadType.COMPRESSABLE) @@ -381,7 +384,7 @@ namespace Grpc.IntegrationTesting ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { AuthScope }); string oauth2Token = await credential.GetAccessTokenForRequestAsync(); - client.HeaderInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token); + client.HeaderInterceptor = AuthInterceptors.FromAccessToken(oauth2Token); var request = SimpleRequest.CreateBuilder() .SetFillUsername(true) @@ -401,7 +404,7 @@ namespace Grpc.IntegrationTesting ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { AuthScope }); string oauth2Token = await credential.GetAccessTokenForRequestAsync(); - var headerInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token); + var headerInterceptor = AuthInterceptors.FromAccessToken(oauth2Token); var request = SimpleRequest.CreateBuilder() .SetFillUsername(true) @@ -409,7 +412,7 @@ namespace Grpc.IntegrationTesting .Build(); var headers = new Metadata(); - headerInterceptor("", headers); + headerInterceptor(null, "", headers); var response = client.UnaryCall(request, headers: headers); Assert.AreEqual(AuthScopeResponse, response.OauthScope); @@ -458,6 +461,29 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } + public static async Task RunTimeoutOnSleepingServerAsync(TestService.ITestServiceClient client) + { + Console.WriteLine("running timeout_on_sleeping_server"); + + var deadline = DateTime.UtcNow.AddMilliseconds(1); + using (var call = client.FullDuplexCall(deadline: deadline)) + { + try + { + await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder() + .SetPayload(CreateZerosPayload(27182)).Build()); + } + catch (InvalidOperationException) + { + // Deadline was reached before write has started. Eat the exception and continue. + } + + var ex = Assert.Throws<RpcException>(async () => await call.ResponseStream.MoveNext()); + Assert.AreEqual(StatusCode.DeadlineExceeded, ex.Status.StatusCode); + } + Console.WriteLine("Passed!"); + } + // This is not an official interop test, but it's useful. public static void RunBenchmarkEmptyUnary(TestService.ITestServiceClient client) { diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs index 6fa721bc1c..f3158aeb45 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs @@ -75,9 +75,8 @@ namespace Grpc.IntegrationTesting [TestFixtureTearDown] public void Cleanup() { - channel.Dispose(); + channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); - GrpcEnvironment.Shutdown(); } [Test] @@ -127,5 +126,11 @@ namespace Grpc.IntegrationTesting { await InteropClient.RunCancelAfterFirstResponseAsync(client); } + + [Test] + public async Task TimeoutOnSleepingServerAsync() + { + await InteropClient.RunTimeoutOnSleepingServerAsync(client); + } } } diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs index 504fd11857..0cc8b2cde1 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs @@ -107,8 +107,6 @@ namespace Grpc.IntegrationTesting server.Start(); server.ShutdownTask.Wait(); - - GrpcEnvironment.Shutdown(); } private static ServerOptions ParseArguments(string[] args) diff --git a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs index 1c398eb84e..842795374f 100644 --- a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs @@ -85,9 +85,8 @@ namespace Grpc.IntegrationTesting [TestFixtureTearDown] public void Cleanup() { - channel.Dispose(); + channel.ShutdownAsync().Wait(); server.ShutdownAsync().Wait(); - GrpcEnvironment.Shutdown(); } [Test] diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index bf2bbd873b..fc9470f93f 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -510,22 +510,27 @@ grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx, ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; ops[0].flags = 0; + ops[0].reserved = NULL; ops[1].op = GRPC_OP_SEND_MESSAGE; ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len); ops[1].data.send_message = ctx->send_message; ops[1].flags = write_flags; + ops[1].reserved = NULL; ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; ops[2].flags = 0; + ops[2].reserved = NULL; ops[3].op = GRPC_OP_RECV_INITIAL_METADATA; ops[3].data.recv_initial_metadata = &(ctx->recv_initial_metadata); ops[3].flags = 0; + ops[3].reserved = NULL; ops[4].op = GRPC_OP_RECV_MESSAGE; ops[4].data.recv_message = &(ctx->recv_message); ops[4].flags = 0; + ops[4].reserved = NULL; ops[5].op = GRPC_OP_RECV_STATUS_ON_CLIENT; ops[5].data.recv_status_on_client.trailing_metadata = @@ -538,6 +543,7 @@ grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx, ops[5].data.recv_status_on_client.status_details_capacity = &(ctx->recv_status_on_client.status_details_capacity); ops[5].flags = 0; + ops[5].reserved = NULL; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); @@ -556,14 +562,17 @@ grpcsharp_call_start_client_streaming(grpc_call *call, ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; ops[0].flags = 0; + ops[0].reserved = NULL; ops[1].op = GRPC_OP_RECV_INITIAL_METADATA; ops[1].data.recv_initial_metadata = &(ctx->recv_initial_metadata); ops[1].flags = 0; + ops[1].reserved = NULL; ops[2].op = GRPC_OP_RECV_MESSAGE; ops[2].data.recv_message = &(ctx->recv_message); ops[2].flags = 0; + ops[2].reserved = NULL; ops[3].op = GRPC_OP_RECV_STATUS_ON_CLIENT; ops[3].data.recv_status_on_client.trailing_metadata = @@ -576,6 +585,7 @@ grpcsharp_call_start_client_streaming(grpc_call *call, ops[3].data.recv_status_on_client.status_details_capacity = &(ctx->recv_status_on_client.status_details_capacity); ops[3].flags = 0; + ops[3].reserved = NULL; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); @@ -593,18 +603,22 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming( ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; ops[0].flags = 0; + ops[0].reserved = NULL; ops[1].op = GRPC_OP_SEND_MESSAGE; ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len); ops[1].data.send_message = ctx->send_message; ops[1].flags = write_flags; + ops[1].reserved = NULL; ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; ops[2].flags = 0; + ops[2].reserved = NULL; ops[3].op = GRPC_OP_RECV_INITIAL_METADATA; ops[3].data.recv_initial_metadata = &(ctx->recv_initial_metadata); ops[3].flags = 0; + ops[3].reserved = NULL; ops[4].op = GRPC_OP_RECV_STATUS_ON_CLIENT; ops[4].data.recv_status_on_client.trailing_metadata = @@ -617,6 +631,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming( ops[4].data.recv_status_on_client.status_details_capacity = &(ctx->recv_status_on_client.status_details_capacity); ops[4].flags = 0; + ops[4].reserved = NULL; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); @@ -635,10 +650,12 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call, ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; ops[0].flags = 0; + ops[0].reserved = NULL; ops[1].op = GRPC_OP_RECV_INITIAL_METADATA; ops[1].data.recv_initial_metadata = &(ctx->recv_initial_metadata); ops[1].flags = 0; + ops[1].reserved = NULL; ops[2].op = GRPC_OP_RECV_STATUS_ON_CLIENT; ops[2].data.recv_status_on_client.trailing_metadata = @@ -651,6 +668,7 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call, ops[2].data.recv_status_on_client.status_details_capacity = &(ctx->recv_status_on_client.status_details_capacity); ops[2].flags = 0; + ops[2].reserved = NULL; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); @@ -668,10 +686,12 @@ grpcsharp_call_send_message(grpc_call *call, grpcsharp_batch_context *ctx, ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len); ops[0].data.send_message = ctx->send_message; ops[0].flags = write_flags; + ops[0].reserved = NULL; ops[1].op = GRPC_OP_SEND_INITIAL_METADATA; ops[1].data.send_initial_metadata.count = 0; ops[1].data.send_initial_metadata.metadata = NULL; ops[1].flags = 0; + ops[1].reserved = NULL; return grpc_call_start_batch(call, ops, nops, ctx, NULL); } @@ -683,6 +703,7 @@ grpcsharp_call_send_close_from_client(grpc_call *call, grpc_op ops[1]; ops[0].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; ops[0].flags = 0; + ops[0].reserved = NULL; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); @@ -706,10 +727,12 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server( ops[0].data.send_status_from_server.trailing_metadata = ctx->send_status_from_server.trailing_metadata.metadata; ops[0].flags = 0; + ops[0].reserved = NULL; ops[1].op = GRPC_OP_SEND_INITIAL_METADATA; ops[1].data.send_initial_metadata.count = 0; ops[1].data.send_initial_metadata.metadata = NULL; ops[1].flags = 0; + ops[1].reserved = NULL; return grpc_call_start_batch(call, ops, nops, ctx, NULL); } @@ -721,6 +744,7 @@ grpcsharp_call_recv_message(grpc_call *call, grpcsharp_batch_context *ctx) { ops[0].op = GRPC_OP_RECV_MESSAGE; ops[0].data.recv_message = &(ctx->recv_message); ops[0].flags = 0; + ops[0].reserved = NULL; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } @@ -733,6 +757,7 @@ grpcsharp_call_start_serverside(grpc_call *call, grpcsharp_batch_context *ctx) { ops[0].data.recv_close_on_server.cancelled = (&ctx->recv_close_on_server_cancelled); ops[0].flags = 0; + ops[0].reserved = NULL; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); @@ -751,6 +776,7 @@ grpcsharp_call_send_initial_metadata(grpc_call *call, ops[0].data.send_initial_metadata.metadata = ctx->send_initial_metadata.metadata; ops[0].flags = 0; + ops[0].reserved = NULL; return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); diff --git a/src/node/README.md b/src/node/README.md index 7d3d8c7fa1..b6411537c7 100644 --- a/src/node/README.md +++ b/src/node/README.md @@ -5,11 +5,35 @@ Alpha : Ready for early adopters ## PREREQUISITES - `node`: This requires `node` to be installed. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package. -- [homebrew][] on Mac OS X, [linuxbrew][] on Linux. These simplify the installation of the gRPC C core. +- [homebrew][] on Mac OS X. These simplify the installation of the gRPC C core. ## INSTALLATION -On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][]. -Run the following command to install gRPC Node.js. + +**Linux (Debian):** + +Add [Debian unstable][] to your `sources.list` file. Example: + +```sh +echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" | \ +sudo tee -a /etc/apt/sources.list +``` + +Install the gRPC Debian package + +```sh +sudo apt-get update +sudo apt-get install libgrpc-dev +``` + +Install the gRPC NPM package + +```sh +npm install grpc +``` + +**Mac OS X** + +Install [homebrew][]. Run the following command to install gRPC Node.js. ```sh $ curl -fsSL https://goo.gl/getgrpc | bash -s nodejs ``` @@ -88,5 +112,5 @@ ServerCredentials An object with factory methods for creating credential objects for servers. [homebrew]:http://brew.sh -[linuxbrew]:https://github.com/Homebrew/linuxbrew#installation [gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install +[Debian unstable]:https://www.debian.org/releases/sid/ diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc index 6fc1bc424f..18858fa334 100644 --- a/src/node/ext/call.cc +++ b/src/node/ext/call.cc @@ -207,6 +207,13 @@ class SendMessageOp : public Op { if (!::node::Buffer::HasInstance(value)) { return false; } + Handle<Object> object_value = value->ToObject(); + if (object_value->HasOwnProperty(NanNew("grpcWriteFlags"))) { + Handle<Value> flag_value = object_value->Get(NanNew("grpcWriteFlags")); + if (flag_value->IsUint32()) { + out->flags = flag_value->Uint32Value() & GRPC_WRITE_USED_MASK; + } + } out->data.send_message = BufferToByteBuffer(value); Persistent<Value> *handle = new Persistent<Value>(); NanAssignPersistent(*handle, value); @@ -457,10 +464,6 @@ void Call::Init(Handle<Object> exports) { NanNew<FunctionTemplate>(GetPeer)->GetFunction()); NanAssignPersistent(fun_tpl, tpl); Handle<Function> ctr = tpl->GetFunction(); - ctr->Set(NanNew("WRITE_BUFFER_HINT"), - NanNew<Uint32, uint32_t>(GRPC_WRITE_BUFFER_HINT)); - ctr->Set(NanNew("WRITE_NO_COMPRESS"), - NanNew<Uint32, uint32_t>(GRPC_WRITE_NO_COMPRESS)); exports->Set(NanNew("Call"), ctr); constructor = new NanCallback(ctr); } @@ -502,6 +505,22 @@ NAN_METHOD(Call::New) { return NanThrowTypeError( "Call's third argument must be a date or a number"); } + // These arguments are at the end because they are optional + grpc_call *parent_call = NULL; + if (Call::HasInstance(args[4])) { + Call *parent_obj = ObjectWrap::Unwrap<Call>(args[4]->ToObject()); + parent_call = parent_obj->wrapped_call; + } else if (!(args[4]->IsUndefined() || args[4]->IsNull())) { + return NanThrowTypeError( + "Call's fifth argument must be another call, if provided"); + } + gpr_uint32 propagate_flags = GRPC_PROPAGATE_DEFAULTS; + if (args[5]->IsUint32()) { + propagate_flags = args[5]->Uint32Value(); + } else if (!(args[5]->IsUndefined() || args[5]->IsNull())) { + return NanThrowTypeError( + "Call's sixth argument must be propagate flags, if provided"); + } Handle<Object> channel_object = args[0]->ToObject(); Channel *channel = ObjectWrap::Unwrap<Channel>(channel_object); if (channel->GetWrappedChannel() == NULL) { @@ -514,12 +533,12 @@ NAN_METHOD(Call::New) { if (args[3]->IsString()) { NanUtf8String host_override(args[3]); wrapped_call = grpc_channel_create_call( - wrapped_channel, NULL, GRPC_PROPAGATE_DEFAULTS, + wrapped_channel, parent_call, propagate_flags, CompletionQueueAsyncWorker::GetQueue(), *method, *host_override, MillisecondsToTimespec(deadline), NULL); } else if (args[3]->IsUndefined() || args[3]->IsNull()) { wrapped_call = grpc_channel_create_call( - wrapped_channel, NULL, GRPC_PROPAGATE_DEFAULTS, + wrapped_channel, parent_call, propagate_flags, CompletionQueueAsyncWorker::GetQueue(), *method, NULL, MillisecondsToTimespec(deadline), NULL); } else { @@ -565,6 +584,7 @@ NAN_METHOD(Call::StartBatch) { uint32_t type = keys->Get(i)->Uint32Value(); ops[i].op = static_cast<grpc_op_type>(type); ops[i].flags = 0; + ops[i].reserved = NULL; switch (type) { case GRPC_OP_SEND_INITIAL_METADATA: op.reset(new SendMetadataOp()); @@ -603,7 +623,7 @@ NAN_METHOD(Call::StartBatch) { call->wrapped_call, &ops[0], nops, new struct tag( callback, op_vector.release(), resources), NULL); if (error != GRPC_CALL_OK) { - return NanThrowError("startBatch failed", error); + return NanThrowError(nanErrorWithCode("startBatch failed", error)); } CompletionQueueAsyncWorker::Next(); NanReturnUndefined(); @@ -617,7 +637,7 @@ NAN_METHOD(Call::Cancel) { Call *call = ObjectWrap::Unwrap<Call>(args.This()); grpc_call_error error = grpc_call_cancel(call->wrapped_call, NULL); if (error != GRPC_CALL_OK) { - return NanThrowError("cancel failed", error); + return NanThrowError(nanErrorWithCode("cancel failed", error)); } NanReturnUndefined(); } diff --git a/src/node/ext/call.h b/src/node/ext/call.h index 6acda76197..ef6e5fcd21 100644 --- a/src/node/ext/call.h +++ b/src/node/ext/call.h @@ -51,6 +51,19 @@ namespace node { using std::unique_ptr; using std::shared_ptr; +/** + * Helper function for throwing errors with a grpc_call_error value. + * Modified from the answer by Gus Goose to + * http://stackoverflow.com/questions/31794200. + */ +inline v8::Local<v8::Value> nanErrorWithCode(const char *msg, + grpc_call_error code) { + NanEscapableScope(); + v8::Local<v8::Object> err = NanError(msg).As<v8::Object>(); + err->Set(NanNew("code"), NanNew<v8::Uint32>(code)); + return NanEscapeScope(err); +} + v8::Handle<v8::Value> ParseMetadata(const grpc_metadata_array *metadata_array); class PersistentHolder { diff --git a/src/node/ext/node_grpc.cc b/src/node/ext/node_grpc.cc index 331ccb60d6..0cf30da922 100644 --- a/src/node/ext/node_grpc.cc +++ b/src/node/ext/node_grpc.cc @@ -159,6 +159,25 @@ void InitOpTypeConstants(Handle<Object> exports) { op_type->Set(NanNew("RECV_CLOSE_ON_SERVER"), RECV_CLOSE_ON_SERVER); } +void InitPropagateConstants(Handle<Object> exports) { + NanScope(); + Handle<Object> propagate = NanNew<Object>(); + exports->Set(NanNew("propagate"), propagate); + Handle<Value> DEADLINE(NanNew<Uint32, uint32_t>(GRPC_PROPAGATE_DEADLINE)); + propagate->Set(NanNew("DEADLINE"), DEADLINE); + Handle<Value> CENSUS_STATS_CONTEXT( + NanNew<Uint32, uint32_t>(GRPC_PROPAGATE_CENSUS_STATS_CONTEXT)); + propagate->Set(NanNew("CENSUS_STATS_CONTEXT"), CENSUS_STATS_CONTEXT); + Handle<Value> CENSUS_TRACING_CONTEXT( + NanNew<Uint32, uint32_t>(GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT)); + propagate->Set(NanNew("CENSUS_TRACING_CONTEXT"), CENSUS_TRACING_CONTEXT); + Handle<Value> CANCELLATION( + NanNew<Uint32, uint32_t>(GRPC_PROPAGATE_CANCELLATION)); + propagate->Set(NanNew("CANCELLATION"), CANCELLATION); + Handle<Value> DEFAULTS(NanNew<Uint32, uint32_t>(GRPC_PROPAGATE_DEFAULTS)); + propagate->Set(NanNew("DEFAULTS"), DEFAULTS); +} + void InitConnectivityStateConstants(Handle<Object> exports) { NanScope(); Handle<Object> channel_state = NanNew<Object>(); @@ -177,13 +196,25 @@ void InitConnectivityStateConstants(Handle<Object> exports) { channel_state->Set(NanNew("FATAL_FAILURE"), FATAL_FAILURE); } +void InitWriteFlags(Handle<Object> exports) { + NanScope(); + Handle<Object> write_flags = NanNew<Object>(); + exports->Set(NanNew("writeFlags"), write_flags); + Handle<Value> BUFFER_HINT(NanNew<Uint32, uint32_t>(GRPC_WRITE_BUFFER_HINT)); + write_flags->Set(NanNew("BUFFER_HINT"), BUFFER_HINT); + Handle<Value> NO_COMPRESS(NanNew<Uint32, uint32_t>(GRPC_WRITE_NO_COMPRESS)); + write_flags->Set(NanNew("NO_COMPRESS"), NO_COMPRESS); +} + void init(Handle<Object> exports) { NanScope(); grpc_init(); InitStatusConstants(exports); InitCallErrorConstants(exports); InitOpTypeConstants(exports); + InitPropagateConstants(exports); InitConnectivityStateConstants(exports); + InitWriteFlags(exports); grpc::node::Call::Init(exports); grpc::node::Channel::Init(exports); diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc index 8e39644846..01217bce79 100644 --- a/src/node/ext/server.cc +++ b/src/node/ext/server.cc @@ -235,7 +235,7 @@ NAN_METHOD(Server::RequestCall) { new struct tag(new NanCallback(args[0].As<Function>()), ops.release(), shared_ptr<Resources>(nullptr))); if (error != GRPC_CALL_OK) { - return NanThrowError("requestCall failed", error); + return NanThrowError(nanErrorWithCode("requestCall failed", error)); } CompletionQueueAsyncWorker::Next(); NanReturnUndefined(); diff --git a/src/node/health_check/health.js b/src/node/health_check/health.js index 87e00197fe..84d7e0568e 100644 --- a/src/node/health_check/health.js +++ b/src/node/health_check/health.js @@ -45,17 +45,13 @@ function HealthImplementation(statusMap) { this.statusMap = _.clone(statusMap); } -HealthImplementation.prototype.setStatus = function(host, service, status) { - if (!this.statusMap[host]) { - this.statusMap[host] = {}; - } - this.statusMap[host][service] = status; +HealthImplementation.prototype.setStatus = function(service, status) { + this.statusMap[service] = status; }; HealthImplementation.prototype.check = function(call, callback){ - var host = call.request.host; var service = call.request.service; - var status = _.get(this.statusMap, [host, service], null); + var status = _.get(this.statusMap, service, null); if (status === null) { callback({code:grpc.status.NOT_FOUND}); } else { diff --git a/src/node/health_check/health.proto b/src/node/health_check/health.proto index d31df1e0a7..57f4aaa9c0 100644 --- a/src/node/health_check/health.proto +++ b/src/node/health_check/health.proto @@ -32,8 +32,7 @@ syntax = "proto3"; package grpc.health.v1alpha; message HealthCheckRequest { - string host = 1; - string service = 2; + string service = 1; } message HealthCheckResponse { @@ -47,4 +46,4 @@ message HealthCheckResponse { service Health { rpc Check(HealthCheckRequest) returns (HealthCheckResponse); -}
\ No newline at end of file +} diff --git a/src/node/index.js b/src/node/index.js index b26ab35f2c..889b0ac0e9 100644 --- a/src/node/index.js +++ b/src/node/index.js @@ -135,11 +135,21 @@ exports.Server = server.Server; exports.status = grpc.status; /** + * Propagate flag name to number mapping + */ +exports.propagate = grpc.propagate; + +/** * Call error name to code number mapping */ exports.callError = grpc.callError; /** + * Write flag name to code number mapping + */ +exports.writeFlags = grpc.writeFlags; + +/** * Credentials factories */ exports.Credentials = grpc.Credentials; diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js index 8ff9b3cff7..9100edf243 100644 --- a/src/node/interop/interop_client.js +++ b/src/node/interop/interop_client.js @@ -264,7 +264,9 @@ function timeoutOnSleepingServer(client, done) { payload: {body: zeroBuffer(27182)} }); call.on('error', function(error) { - assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); + + assert(error.code === grpc.status.DEADLINE_EXCEEDED || + error.code === grpc.status.INTERNAL); done(); }); } diff --git a/src/node/src/client.js b/src/node/src/client.js index 90791b4e4c..f288104e2b 100644 --- a/src/node/src/client.js +++ b/src/node/src/client.js @@ -79,13 +79,19 @@ function ClientWritableStream(call, serialize) { * implementation of a method needed for implementing stream.Writable. * @access private * @param {Buffer} chunk The chunk to write - * @param {string} encoding Ignored + * @param {string} encoding Used to pass write flags * @param {function(Error=)} callback Called when the write is complete */ function _write(chunk, encoding, callback) { /* jshint validthis: true */ var batch = {}; - batch[grpc.opType.SEND_MESSAGE] = this.serialize(chunk); + var message = this.serialize(chunk); + if (_.isFinite(encoding)) { + /* Attach the encoding if it is a finite number. This is the closest we + * can get to checking that it is valid flags */ + message.grpcWriteFlags = encoding; + } + batch[grpc.opType.SEND_MESSAGE] = message; this.call.startBatch(batch, function(err, event) { if (err) { // Something has gone wrong. Stop writing by failing to call callback @@ -216,14 +222,19 @@ ClientDuplexStream.prototype.getPeer = getPeer; function getCall(channel, method, options) { var deadline; var host; + var parent; + var propagate_flags; if (options) { deadline = options.deadline; host = options.host; + parent = _.get(options, 'parent.call'); + propagate_flags = options.propagate_flags; } if (deadline === undefined) { deadline = Infinity; } - return new grpc.Call(channel, method, deadline, host); + return new grpc.Call(channel, method, deadline, host, + parent, propagate_flags); } /** @@ -268,8 +279,12 @@ function makeUnaryRequestFunction(method, serialize, deserialize) { return; } var client_batch = {}; + var message = serialize(argument); + if (options) { + message.grpcWriteFlags = options.flags; + } client_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata; - client_batch[grpc.opType.SEND_MESSAGE] = serialize(argument); + client_batch[grpc.opType.SEND_MESSAGE] = message; client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; client_batch[grpc.opType.RECV_MESSAGE] = true; @@ -402,9 +417,13 @@ function makeServerStreamRequestFunction(method, serialize, deserialize) { return; } var start_batch = {}; + var message = serialize(argument); + if (options) { + message.grpcWriteFlags = options.flags; + } start_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata; start_batch[grpc.opType.RECV_INITIAL_METADATA] = true; - start_batch[grpc.opType.SEND_MESSAGE] = serialize(argument); + start_batch[grpc.opType.SEND_MESSAGE] = message; start_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; call.startBatch(start_batch, function(err, response) { if (err) { diff --git a/src/node/src/server.js b/src/node/src/server.js index 5c62f5990c..5037abae43 100644 --- a/src/node/src/server.js +++ b/src/node/src/server.js @@ -115,8 +115,10 @@ function waitForCancel(call, emitter) { * @param {function(*):Buffer=} serialize Serialization function for the * response * @param {Object=} metadata Optional trailing metadata to send with status + * @param {number=} flags Flags for modifying how the message is sent. + * Defaults to 0. */ -function sendUnaryResponse(call, value, serialize, metadata) { +function sendUnaryResponse(call, value, serialize, metadata, flags) { var end_batch = {}; var status = { code: grpc.status.OK, @@ -130,7 +132,9 @@ function sendUnaryResponse(call, value, serialize, metadata) { end_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; call.metadataSent = true; } - end_batch[grpc.opType.SEND_MESSAGE] = serialize(value); + var message = serialize(value); + message.grpcWriteFlags = flags; + end_batch[grpc.opType.SEND_MESSAGE] = message; end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status; call.startBatch(end_batch, function (){}); } @@ -254,7 +258,7 @@ function ServerWritableStream(call, serialize) { * for implementing stream.Writable. * @access private * @param {Buffer} chunk The chunk of data to write - * @param {string} encoding Ignored + * @param {string} encoding Used to pass write flags * @param {function(Error=)} callback Callback to indicate that the write is * complete */ @@ -265,7 +269,13 @@ function _write(chunk, encoding, callback) { batch[grpc.opType.SEND_INITIAL_METADATA] = {}; this.call.metadataSent = true; } - batch[grpc.opType.SEND_MESSAGE] = this.serialize(chunk); + var message = this.serialize(chunk); + if (_.isFinite(encoding)) { + /* Attach the encoding if it is a finite number. This is the closest we + * can get to checking that it is valid flags */ + message.grpcWriteFlags = encoding; + } + batch[grpc.opType.SEND_MESSAGE] = message; this.call.startBatch(batch, function(err, value) { if (err) { this.emit('error', err); @@ -432,6 +442,7 @@ function handleUnary(call, handler, metadata) { }); emitter.metadata = metadata; waitForCancel(call, emitter); + emitter.call = call; var batch = {}; batch[grpc.opType.RECV_MESSAGE] = true; call.startBatch(batch, function(err, result) { @@ -449,14 +460,14 @@ function handleUnary(call, handler, metadata) { if (emitter.cancelled) { return; } - handler.func(emitter, function sendUnaryData(err, value, trailer) { + handler.func(emitter, function sendUnaryData(err, value, trailer, flags) { if (err) { if (trailer) { err.metadata = trailer; } handleError(call, err); } else { - sendUnaryResponse(call, value, handler.serialize, trailer); + sendUnaryResponse(call, value, handler.serialize, trailer, flags); } }); }); @@ -513,7 +524,7 @@ function handleClientStreaming(call, handler, metadata) { }); waitForCancel(call, stream); stream.metadata = metadata; - handler.func(stream, function(err, value, trailer) { + handler.func(stream, function(err, value, trailer, flags) { stream.terminate(); if (err) { if (trailer) { @@ -521,7 +532,7 @@ function handleClientStreaming(call, handler, metadata) { } handleError(call, err); } else { - sendUnaryResponse(call, value, handler.serialize, trailer); + sendUnaryResponse(call, value, handler.serialize, trailer, flags); } }); } diff --git a/src/node/test/constant_test.js b/src/node/test/constant_test.js index 93bf0c8ada..fa06ad4e4d 100644 --- a/src/node/test/constant_test.js +++ b/src/node/test/constant_test.js @@ -79,6 +79,18 @@ var callErrorNames = [ ]; /** + * List of all propagate flag names + * @const + * @type {Array.<string>} + */ +var propagateFlagNames = [ + 'DEADLINE', + 'CENSUS_STATS_CONTEXT', + 'CENSUS_TRACING_CONTEXT', + 'CANCELLATION', + 'DEFAULTS' +]; +/* * List of all connectivity state names * @const * @type {Array.<string>} @@ -104,6 +116,12 @@ describe('constants', function() { 'call error missing: ' + callErrorNames[i]); } }); + it('should have all of the propagate flags', function() { + for (var i = 0; i < propagateFlagNames.length; i++) { + assert(grpc.propagate.hasOwnProperty(propagateFlagNames[i]), + 'call error missing: ' + propagateFlagNames[i]); + } + }); it('should have all of the connectivity states', function() { for (var i = 0; i < connectivityStateNames.length; i++) { assert(grpc.connectivityState.hasOwnProperty(connectivityStateNames[i]), diff --git a/src/node/test/health_test.js b/src/node/test/health_test.js index be4ef1d251..04959f5f55 100644 --- a/src/node/test/health_test.js +++ b/src/node/test/health_test.js @@ -41,13 +41,9 @@ var grpc = require('../'); describe('Health Checking', function() { var statusMap = { - '': { - '': 'SERVING', - 'grpc.test.TestService': 'NOT_SERVING', - }, - virtual_host: { - 'grpc.test.TestService': 'SERVING' - } + '': 'SERVING', + 'grpc.test.TestServiceNotServing': 'NOT_SERVING', + 'grpc.test.TestServiceServing': 'SERVING' }; var healthServer = new grpc.Server(); healthServer.addProtoService(health.service, @@ -71,15 +67,15 @@ describe('Health Checking', function() { }); }); it('should say that a disabled service is NOT_SERVING', function(done) { - healthClient.check({service: 'grpc.test.TestService'}, + healthClient.check({service: 'grpc.test.TestServiceNotServing'}, function(err, response) { assert.ifError(err); assert.strictEqual(response.status, 'NOT_SERVING'); done(); }); }); - it('should say that a service on another host is SERVING', function(done) { - healthClient.check({host: 'virtual_host', service: 'grpc.test.TestService'}, + it('should say that an enabled service is SERVING', function(done) { + healthClient.check({service: 'grpc.test.TestServiceServing'}, function(err, response) { assert.ifError(err); assert.strictEqual(response.status, 'SERVING'); @@ -93,12 +89,4 @@ describe('Health Checking', function() { done(); }); }); - it('should get NOT_FOUND if the host is not registered', function(done) { - healthClient.check({host: 'wrong_host', service: 'grpc.test.TestService'}, - function(err, response) { - assert(err); - assert.strictEqual(err.code, grpc.status.NOT_FOUND); - done(); - }); - }); }); diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js index 34c64141f3..c2b9323abf 100644 --- a/src/node/test/surface_test.js +++ b/src/node/test/surface_test.js @@ -67,6 +67,7 @@ function multiDone(done, count) { } }; } + var server_insecure_creds = grpc.ServerCredentials.createInsecure(); describe('File loader', function() { @@ -362,12 +363,14 @@ describe('Echo metadata', function() { }); }); describe('Other conditions', function() { + var test_service; + var Client; var client; var server; var port; before(function() { var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto'); - var test_service = test_proto.lookup('TestService'); + test_service = test_proto.lookup('TestService'); server = new grpc.Server(); server.addProtoService(test_service, { unary: function(call, cb) { @@ -429,7 +432,7 @@ describe('Other conditions', function() { } }); port = server.bind('localhost:0', server_insecure_creds); - var Client = surface_client.makeProtobufClientConstructor(test_service); + Client = surface_client.makeProtobufClientConstructor(test_service); client = new Client('localhost:' + port, grpc.Credentials.createInsecure()); server.start(); }); @@ -682,6 +685,168 @@ describe('Other conditions', function() { }); }); }); + describe('Call propagation', function() { + var proxy; + var proxy_impl; + beforeEach(function() { + proxy = new grpc.Server(); + proxy_impl = { + unary: function(call) {}, + clientStream: function(stream) {}, + serverStream: function(stream) {}, + bidiStream: function(stream) {} + }; + }); + afterEach(function() { + console.log('Shutting down server'); + proxy.shutdown(); + }); + describe('Cancellation', function() { + it('With a unary call', function(done) { + done = multiDone(done, 2); + proxy_impl.unary = function(parent, callback) { + client.unary(parent.request, function(err, value) { + try { + assert(err); + assert.strictEqual(err.code, grpc.status.CANCELLED); + } finally { + callback(err, value); + done(); + } + }, null, {parent: parent}); + call.cancel(); + }; + proxy.addProtoService(test_service, proxy_impl); + var proxy_port = proxy.bind('localhost:0', server_insecure_creds); + proxy.start(); + var proxy_client = new Client('localhost:' + proxy_port, + grpc.Credentials.createInsecure()); + var call = proxy_client.unary({}, function(err, value) { + done(); + }); + }); + it('With a client stream call', function(done) { + done = multiDone(done, 2); + proxy_impl.clientStream = function(parent, callback) { + client.clientStream(function(err, value) { + try { + assert(err); + assert.strictEqual(err.code, grpc.status.CANCELLED); + } finally { + callback(err, value); + done(); + } + }, null, {parent: parent}); + call.cancel(); + }; + proxy.addProtoService(test_service, proxy_impl); + var proxy_port = proxy.bind('localhost:0', server_insecure_creds); + proxy.start(); + var proxy_client = new Client('localhost:' + proxy_port, + grpc.Credentials.createInsecure()); + var call = proxy_client.clientStream(function(err, value) { + done(); + }); + }); + it('With a server stream call', function(done) { + done = multiDone(done, 2); + proxy_impl.serverStream = function(parent) { + var child = client.serverStream(parent.request, null, + {parent: parent}); + child.on('error', function(err) { + assert(err); + assert.strictEqual(err.code, grpc.status.CANCELLED); + done(); + }); + call.cancel(); + }; + proxy.addProtoService(test_service, proxy_impl); + var proxy_port = proxy.bind('localhost:0', server_insecure_creds); + proxy.start(); + var proxy_client = new Client('localhost:' + proxy_port, + grpc.Credentials.createInsecure()); + var call = proxy_client.serverStream({}); + call.on('error', function(err) { + done(); + }); + }); + it('With a bidi stream call', function(done) { + done = multiDone(done, 2); + proxy_impl.bidiStream = function(parent) { + var child = client.bidiStream(null, {parent: parent}); + child.on('error', function(err) { + assert(err); + assert.strictEqual(err.code, grpc.status.CANCELLED); + done(); + }); + call.cancel(); + }; + proxy.addProtoService(test_service, proxy_impl); + var proxy_port = proxy.bind('localhost:0', server_insecure_creds); + proxy.start(); + var proxy_client = new Client('localhost:' + proxy_port, + grpc.Credentials.createInsecure()); + var call = proxy_client.bidiStream(); + call.on('error', function(err) { + done(); + }); + }); + }); + describe('Deadline', function() { + /* jshint bitwise:false */ + var deadline_flags = (grpc.propagate.DEFAULTS & + ~grpc.propagate.CANCELLATION); + it('With a client stream call', function(done) { + done = multiDone(done, 2); + proxy_impl.clientStream = function(parent, callback) { + client.clientStream(function(err, value) { + try { + assert(err); + assert(err.code === grpc.status.DEADLINE_EXCEEDED || + err.code === grpc.status.INTERNAL); + } finally { + callback(err, value); + done(); + } + }, null, {parent: parent, propagate_flags: deadline_flags}); + }; + proxy.addProtoService(test_service, proxy_impl); + var proxy_port = proxy.bind('localhost:0', server_insecure_creds); + proxy.start(); + var proxy_client = new Client('localhost:' + proxy_port, + grpc.Credentials.createInsecure()); + var deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + 1); + proxy_client.clientStream(function(err, value) { + done(); + }, null, {deadline: deadline}); + }); + it('With a bidi stream call', function(done) { + done = multiDone(done, 2); + proxy_impl.bidiStream = function(parent) { + var child = client.bidiStream( + null, {parent: parent, propagate_flags: deadline_flags}); + child.on('error', function(err) { + assert(err); + assert(err.code === grpc.status.DEADLINE_EXCEEDED || + err.code === grpc.status.INTERNAL); + done(); + }); + }; + proxy.addProtoService(test_service, proxy_impl); + var proxy_port = proxy.bind('localhost:0', server_insecure_creds); + proxy.start(); + var proxy_client = new Client('localhost:' + proxy_port, + grpc.Credentials.createInsecure()); + var deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + 1); + var call = proxy_client.bidiStream(null, {deadline: deadline}); + call.on('error', function(err) { + done(); + }); + }); + }); + }); }); describe('Cancelling surface client', function() { var client; diff --git a/src/php/README.md b/src/php/README.md index 1804606e09..f432935fde 100644 --- a/src/php/README.md +++ b/src/php/README.md @@ -7,17 +7,17 @@ This directory contains source code for PHP implementation of gRPC layered on sh Alpha : Ready for early adopters -## ENVIRONMENT +## Environment Prerequisite: PHP 5.5 or later, `phpunit`, `pecl` -Linux: +**Linux:** ```sh $ sudo apt-get install php5 php5-dev phpunit php-pear ``` -OS X: +**Mac OS X:** ```sh $ curl https://phar.phpunit.de/phpunit.phar -o phpunit.phar @@ -28,10 +28,39 @@ $ curl -O http://pear.php.net/go-pear.phar $ sudo php -d detect_unicode=0 go-pear.phar ``` -## Build from Homebrew +## Quick Install -On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][]. Run the following command to -install gRPC. +**Linux (Debian):** + +Add [Debian unstable][] to your `sources.list` file. Example: + +```sh +echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" | \ +sudo tee -a /etc/apt/sources.list +``` + +Install the gRPC Debian package + +```sh +sudo apt-get update +sudo apt-get install libgrpc-dev +``` + +Install the gRPC PHP extension + +```sh +sudo pecl install grpc-alpha +``` + +**Mac OS X:** + +Install [homebrew][]. Example: + +```sh +ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +``` + +Install the gRPC core library and the PHP extension in one step ```sh $ curl -fsSL https://goo.gl/getgrpc | bash -s php @@ -39,6 +68,7 @@ $ curl -fsSL https://goo.gl/getgrpc | bash -s php This will download and run the [gRPC install script][] and compile the gRPC PHP extension. + ## Build from Source Clone this repository @@ -71,7 +101,7 @@ $ sudo make install Install the gRPC PHP extension ```sh -$ sudo pecl install grpc +$ sudo pecl install grpc-alpha ``` OR @@ -140,6 +170,6 @@ $ ./bin/run_gen_code_test.sh ``` [homebrew]:http://brew.sh -[linuxbrew]:https://github.com/Homebrew/linuxbrew#installation [gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install [Node]:https://github.com/grpc/grpc/tree/master/src/node/examples +[Debian unstable]:https://www.debian.org/releases/sid/ diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c index 1cf766c312..252623d0c3 100644 --- a/src/php/ext/grpc/call.c +++ b/src/php/ext/grpc/call.c @@ -216,13 +216,18 @@ PHP_METHOD(Call, __construct) { char *method; int method_len; zval *deadline_obj; - /* "OsO" == 1 Object, 1 string, 1 Object */ - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OsO", &channel_obj, - grpc_ce_channel, &method, &method_len, - &deadline_obj, grpc_ce_timeval) == FAILURE) { + char *host_override = NULL; + int host_override_len = 0; + /* "OsO|s" == 1 Object, 1 string, 1 Object, 1 optional string */ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OsO|s", + &channel_obj, grpc_ce_channel, + &method, &method_len, + &deadline_obj, grpc_ce_timeval, + &host_override, &host_override_len) + == FAILURE) { zend_throw_exception( spl_ce_InvalidArgumentException, - "Call expects a Channel, a String, and a Timeval", + "Call expects a Channel, a String, a Timeval and an optional String", 1 TSRMLS_CC); return; } @@ -241,7 +246,7 @@ PHP_METHOD(Call, __construct) { deadline_obj TSRMLS_CC); call->wrapped = grpc_channel_create_call( channel->wrapped, NULL, GRPC_PROPAGATE_DEFAULTS, completion_queue, method, - channel->target, deadline->wrapped, NULL); + host_override, deadline->wrapped, NULL); } /** @@ -273,7 +278,6 @@ PHP_METHOD(Call, startBatch) { grpc_byte_buffer *message; int cancelled; grpc_call_error error; - grpc_event event; zval *result; char *message_str; size_t message_len; @@ -398,6 +402,7 @@ PHP_METHOD(Call, startBatch) { } ops[op_num].op = (grpc_op_type)index; ops[op_num].flags = 0; + ops[op_num].reserved = NULL; op_num++; } error = grpc_call_start_batch(call->wrapped, ops, op_num, call->wrapped, @@ -408,14 +413,8 @@ PHP_METHOD(Call, startBatch) { (long)error TSRMLS_CC); goto cleanup; } - event = grpc_completion_queue_pluck(completion_queue, call->wrapped, - gpr_inf_future(GPR_CLOCK_REALTIME), NULL); - if (!event.success) { - zend_throw_exception(spl_ce_LogicException, - "The batch failed for some reason", - 1 TSRMLS_CC); - goto cleanup; - } + grpc_completion_queue_pluck(completion_queue, call->wrapped, + gpr_inf_future(GPR_CLOCK_REALTIME), NULL); for (int i = 0; i < op_num; i++) { switch(ops[i].op) { case GRPC_OP_SEND_INITIAL_METADATA: diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c index f8ce04d902..7a981675de 100644 --- a/src/php/ext/grpc/channel.c +++ b/src/php/ext/grpc/channel.c @@ -64,7 +64,6 @@ void free_wrapped_grpc_channel(void *object TSRMLS_DC) { if (channel->wrapped != NULL) { grpc_channel_destroy(channel->wrapped); } - efree(channel->target); efree(channel); } @@ -141,9 +140,6 @@ PHP_METHOD(Channel, __construct) { HashTable *array_hash; zval **creds_obj = NULL; wrapped_grpc_credentials *creds = NULL; - zval **override_obj; - char *override; - int override_len; /* "s|a" == 1 string, 1 optional array */ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a", &target, &target_length, &args_array) == FAILURE) { @@ -151,8 +147,6 @@ PHP_METHOD(Channel, __construct) { "Channel expects a string and an array", 1 TSRMLS_CC); return; } - override = target; - override_len = target_length; if (args_array == NULL) { channel->wrapped = grpc_insecure_channel_create(target, NULL, NULL); } else { @@ -169,19 +163,6 @@ PHP_METHOD(Channel, __construct) { *creds_obj TSRMLS_CC); zend_hash_del(array_hash, "credentials", 12); } - if (zend_hash_find(array_hash, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, - sizeof(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG), - (void **)&override_obj) == SUCCESS) { - if (Z_TYPE_PP(override_obj) != IS_STRING) { - zend_throw_exception(spl_ce_InvalidArgumentException, - GRPC_SSL_TARGET_NAME_OVERRIDE_ARG - " must be a string", - 1 TSRMLS_CC); - return; - } - override = Z_STRVAL_PP(override_obj); - override_len = Z_STRLEN_PP(override_obj); - } php_grpc_read_args_array(args_array, &args); if (creds == NULL) { channel->wrapped = grpc_insecure_channel_create(target, &args, NULL); @@ -192,8 +173,6 @@ PHP_METHOD(Channel, __construct) { } efree(args.args); } - channel->target = ecalloc(override_len + 1, sizeof(char)); - memcpy(channel->target, override, override_len); } /** diff --git a/src/php/ext/grpc/channel.h b/src/php/ext/grpc/channel.h index c13fa4c6d7..78a16ed0c9 100755 --- a/src/php/ext/grpc/channel.h +++ b/src/php/ext/grpc/channel.h @@ -53,7 +53,6 @@ typedef struct wrapped_grpc_channel { zend_object std; grpc_channel *wrapped; - char *target; } wrapped_grpc_channel; /* Initializes the Channel class */ diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php index 9d6a77b855..2e980c5eed 100755 --- a/src/php/lib/Grpc/BaseStub.php +++ b/src/php/lib/Grpc/BaseStub.php @@ -110,10 +110,10 @@ class BaseStub { } private function _checkConnectivityState($new_state) { - if ($new_state == Grpc\CHANNEL_READY) { + if ($new_state == \Grpc\CHANNEL_READY) { return true; } - if ($new_state == Grpc\CHANNEL_FATAL_ERROR) { + if ($new_state == \Grpc\CHANNEL_FATAL_FAILURE) { throw new Exception('Failed to connect to server'); } return false; diff --git a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php index 8b7e67f57c..287621d930 100644 --- a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php +++ b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php @@ -39,6 +39,14 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase { protected static $client; protected static $timeout; + public function testWaitForNotReady() { + $this->assertFalse(self::$client->waitForReady(1)); + } + + public function testWaitForReady() { + $this->assertTrue(self::$client->waitForReady(250000)); + } + public function testSimpleRequest() { $div_arg = new math\DivArgs(); $div_arg->setDividend(7); diff --git a/src/php/tests/generated_code/GeneratedCodeTest.php b/src/php/tests/generated_code/GeneratedCodeTest.php index 1e4742fc80..a1a2ce81db 100755 --- a/src/php/tests/generated_code/GeneratedCodeTest.php +++ b/src/php/tests/generated_code/GeneratedCodeTest.php @@ -35,7 +35,7 @@ require 'AbstractGeneratedCodeTest.php'; class GeneratedCodeTest extends AbstractGeneratedCodeTest { public static function setUpBeforeClass() { - self::$client = new math\MathClient(new Grpc\BaseStub( - getenv('GRPC_TEST_HOST'), [])); + self::$client = new math\MathClient( + getenv('GRPC_TEST_HOST'), []); } } diff --git a/src/php/tests/generated_code/GeneratedCodeWithCallbackTest.php b/src/php/tests/generated_code/GeneratedCodeWithCallbackTest.php index f8ec1e7da8..68f57d34ad 100644 --- a/src/php/tests/generated_code/GeneratedCodeWithCallbackTest.php +++ b/src/php/tests/generated_code/GeneratedCodeWithCallbackTest.php @@ -35,13 +35,13 @@ require 'AbstractGeneratedCodeTest.php'; class GeneratedCodeWithCallbackTest extends AbstractGeneratedCodeTest { public static function setUpBeforeClass() { - self::$client = new math\MathClient(new Grpc\BaseStub( + self::$client = new math\MathClient( getenv('GRPC_TEST_HOST'), ['update_metadata' => function($a_hash, $client = array()) { $a_copy = $a_hash; $a_copy['foo'] = ['bar']; return $a_copy; - }])); + }]); } } diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php index 44e6242c29..376d306da0 100755 --- a/src/php/tests/interop/interop_client.php +++ b/src/php/tests/interop/interop_client.php @@ -271,7 +271,7 @@ function cancelAfterFirstResponse($stub) { } function timeoutOnSleepingServer($stub) { - $call = $stub->FullDuplexCall(array('timeout' => 500000)); + $call = $stub->FullDuplexCall(array('timeout' => 1000)); $request = new grpc\testing\StreamingOutputCallRequest(); $request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE); $response_parameters = new grpc\testing\ResponseParameters(); diff --git a/src/php/tests/unit_tests/SecureEndToEndTest.php b/src/php/tests/unit_tests/SecureEndToEndTest.php index f91c006da5..60341b983d 100755 --- a/src/php/tests/unit_tests/SecureEndToEndTest.php +++ b/src/php/tests/unit_tests/SecureEndToEndTest.php @@ -40,13 +40,15 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{ file_get_contents(dirname(__FILE__) . '/../data/server1.key'), file_get_contents(dirname(__FILE__) . '/../data/server1.pem')); $this->server = new Grpc\Server(); - $port = $this->server->addSecureHttp2Port('0.0.0.0:0', + $this->port = $this->server->addSecureHttp2Port('0.0.0.0:0', $server_credentials); $this->server->start(); + $this->host_override = 'foo.test.google.fr'; $this->channel = new Grpc\Channel( - 'localhost:' . $port, + 'localhost:' . $this->port, [ - 'grpc.ssl_target_name_override' => 'foo.test.google.fr', + 'grpc.ssl_target_name_override' => $this->host_override, + 'grpc.default_authority' => $this->host_override, 'credentials' => $credentials ]); } @@ -61,7 +63,8 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{ $status_text = 'xyz'; $call = new Grpc\Call($this->channel, 'dummy_method', - $deadline); + $deadline, + $this->host_override); $event = $call->startBatch([ Grpc\OP_SEND_INITIAL_METADATA => [], @@ -112,7 +115,8 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{ $call = new Grpc\Call($this->channel, 'dummy_method', - $deadline); + $deadline, + $this->host_override); $event = $call->startBatch([ Grpc\OP_SEND_INITIAL_METADATA => [], diff --git a/src/python/README.md b/src/python/README.md index 2beb3a913a..de0142db05 100644 --- a/src/python/README.md +++ b/src/python/README.md @@ -9,12 +9,36 @@ Alpha : Ready for early adopters PREREQUISITES ------------- - Python 2.7, virtualenv, pip -- [homebrew][] on Mac OS X, [linuxbrew][] on Linux. These simplify the installation of the gRPC C core. +- [homebrew][] on Mac OS X. These simplify the installation of the gRPC C core. INSTALLATION ------------- -On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][]. -Run the following command to install gRPC Python. + +**Linux (Debian):** + +Add [Debian unstable][] to your `sources.list` file. Example: + +```sh +echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" | \ +sudo tee -a /etc/apt/sources.list +``` + +Install the gRPC Debian package + +```sh +sudo apt-get update +sudo apt-get install libgrpc-dev +``` + +Install the gRPC Python module + +```sh +sudo pip install grpcio +``` + +**Mac OS X** + +Install [homebrew][]. Run the following command to install gRPC Python. ```sh $ curl -fsSL https://goo.gl/getgrpc | bash -s python ``` @@ -27,11 +51,6 @@ Please read our online documentation for a [Quick Start][] and a [detailed examp BUILDING FROM SOURCE --------------------- - Clone this repository -- Build the gRPC core from the root of the - [gRPC Git repository](https://github.com/grpc/grpc) -``` -$ make shared_c static_c -``` - Use build_python.sh to build the Python code and install it into a virtual environment ``` @@ -60,7 +79,7 @@ $ ../../tools/distrib/python/submit.py ``` [homebrew]:http://brew.sh -[linuxbrew]:https://github.com/Homebrew/linuxbrew#installation [gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install [Quick Start]:http://www.grpc.io/docs/tutorials/basic/python.html [detailed example]:http://www.grpc.io/docs/installation/python.html +[Debian unstable]:https://www.debian.org/releases/sid/ diff --git a/src/python/grpcio/README.rst b/src/python/grpcio/README.rst index 00bdecf56f..c7b5a3bde4 100644 --- a/src/python/grpcio/README.rst +++ b/src/python/grpcio/README.rst @@ -6,7 +6,7 @@ Package for GRPC Python. Dependencies ------------ -Ensure you have installed the gRPC core. On Mac OS X, install homebrew_. On Linux, install linuxbrew_. +Ensure you have installed the gRPC core. On Mac OS X, install homebrew_. Run the following command to install gRPC Python. :: @@ -19,5 +19,4 @@ Otherwise, `install from source`_ .. _`install from source`: https://github.com/grpc/grpc/blob/master/src/python/README.md#building-from-source .. _homebrew: http://brew.sh -.. _linuxbrew: https://github.com/Homebrew/linuxbrew#installation .. _`gRPC install script`: https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install diff --git a/src/python/grpcio/grpc/_adapter/_c/utility.c b/src/python/grpcio/grpc/_adapter/_c/utility.c index 2eea0e18ef..590f7e013a 100644 --- a/src/python/grpcio/grpc/_adapter/_c/utility.c +++ b/src/python/grpcio/grpc/_adapter/_c/utility.c @@ -184,6 +184,7 @@ int pygrpc_produce_op(PyObject *op, grpc_op *result) { return 0; } c_op.op = type; + c_op.reserved = NULL; c_op.flags = PyInt_AsLong(PyTuple_GET_ITEM(op, WRITE_FLAGS_INDEX)); if (PyErr_Occurred()) { return 0; diff --git a/src/python/grpcio/grpc/early_adopter/implementations.py b/src/python/grpcio/grpc/early_adopter/implementations.py index 10919fae69..9c396aa7ad 100644 --- a/src/python/grpcio/grpc/early_adopter/implementations.py +++ b/src/python/grpcio/grpc/early_adopter/implementations.py @@ -41,13 +41,15 @@ from grpc.framework.base import util as _base_utilities from grpc.framework.face import implementations as _face_implementations from grpc.framework.foundation import logging_pool -_THREAD_POOL_SIZE = 8 +_DEFAULT_THREAD_POOL_SIZE = 8 _ONE_DAY_IN_SECONDS = 24 * 60 * 60 class _Server(interfaces.Server): - def __init__(self, breakdown, port, private_key, certificate_chain): + def __init__( + self, breakdown, port, private_key, certificate_chain, + thread_pool_size=_DEFAULT_THREAD_POOL_SIZE): self._lock = threading.Lock() self._breakdown = breakdown self._port = port @@ -56,6 +58,7 @@ class _Server(interfaces.Server): else: self._key_chain_pairs = ((private_key, certificate_chain),) + self._pool_size = thread_pool_size self._pool = None self._back = None self._fore_link = None @@ -63,7 +66,7 @@ class _Server(interfaces.Server): def _start(self): with self._lock: if self._pool is None: - self._pool = logging_pool.pool(_THREAD_POOL_SIZE) + self._pool = logging_pool.pool(self._pool_size) servicer = _face_implementations.servicer( self._pool, self._breakdown.implementations, None) self._back = _base_implementations.back_link( @@ -114,7 +117,8 @@ class _Stub(interfaces.Stub): def __init__( self, breakdown, host, port, secure, root_certificates, private_key, - certificate_chain, metadata_transformer=None, server_host_override=None): + certificate_chain, metadata_transformer=None, server_host_override=None, + thread_pool_size=_DEFAULT_THREAD_POOL_SIZE): self._lock = threading.Lock() self._breakdown = breakdown self._host = host @@ -126,6 +130,7 @@ class _Stub(interfaces.Stub): self._metadata_transformer = metadata_transformer self._server_host_override = server_host_override + self._pool_size = thread_pool_size self._pool = None self._front = None self._rear_link = None @@ -134,7 +139,7 @@ class _Stub(interfaces.Stub): def __enter__(self): with self._lock: if self._pool is None: - self._pool = logging_pool.pool(_THREAD_POOL_SIZE) + self._pool = logging_pool.pool(self._pool_size) self._front = _base_implementations.front_link( self._pool, self._pool, self._pool) self._rear_link = _rear.RearLink( @@ -193,7 +198,7 @@ class _Stub(interfaces.Stub): def stub( service_name, methods, host, port, metadata_transformer=None, secure=False, root_certificates=None, private_key=None, certificate_chain=None, - server_host_override=None): + server_host_override=None, thread_pool_size=_DEFAULT_THREAD_POOL_SIZE): """Constructs an interfaces.Stub. Args: @@ -216,6 +221,8 @@ def stub( certificate chain should be used. server_host_override: (For testing only) the target name used for SSL host name checking. + thread_pool_size: The maximum number of threads to allow in the backing + thread pool. Returns: An interfaces.Stub affording RPC invocation. @@ -224,11 +231,13 @@ def stub( return _Stub( breakdown, host, port, secure, root_certificates, private_key, certificate_chain, server_host_override=server_host_override, - metadata_transformer=metadata_transformer) + metadata_transformer=metadata_transformer, + thread_pool_size=thread_pool_size) def server( - service_name, methods, port, private_key=None, certificate_chain=None): + service_name, methods, port, private_key=None, certificate_chain=None, + thread_pool_size=_DEFAULT_THREAD_POOL_SIZE): """Constructs an interfaces.Server. Args: @@ -242,9 +251,12 @@ def server( private_key: A pem-encoded private key, or None for an insecure server. certificate_chain: A pem-encoded certificate chain, or None for an insecure server. + thread_pool_size: The maximum number of threads to allow in the backing + thread pool. Returns: An interfaces.Server that will serve secure traffic. """ breakdown = _face_utilities.break_down_service(service_name, methods) - return _Server(breakdown, port, private_key, certificate_chain) + return _Server(breakdown, port, private_key, certificate_chain, + thread_pool_size=thread_pool_size) diff --git a/src/ruby/bin/interop/test/cpp/interop/test.rb b/src/python/grpcio/grpc/framework/interfaces/base/__init__.py index 5948b50eaa..7086519106 100644 --- a/src/ruby/bin/interop/test/cpp/interop/test.rb +++ b/src/python/grpcio/grpc/framework/interfaces/base/__init__.py @@ -27,17 +27,4 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: test/cpp/interop/test.proto -require 'google/protobuf' - -require 'test/cpp/interop/empty' -require 'test/cpp/interop/messages' -Google::Protobuf::DescriptorPool.generated_pool.build do -end - -module Grpc - module Testing - end -end diff --git a/src/python/grpcio/grpc/framework/interfaces/base/base.py b/src/python/grpcio/grpc/framework/interfaces/base/base.py new file mode 100644 index 0000000000..9d1651daac --- /dev/null +++ b/src/python/grpcio/grpc/framework/interfaces/base/base.py @@ -0,0 +1,273 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""The base interface of RPC Framework.""" + +import abc +import enum + +# abandonment is referenced from specification in this module. +from grpc.framework.foundation import abandonment # pylint: disable=unused-import + + +class NoSuchMethodError(Exception): + """Indicates that an unrecognized operation has been called.""" + + +@enum.unique +class Outcome(enum.Enum): + """Operation outcomes.""" + + COMPLETED = 'completed' + CANCELLED = 'cancelled' + EXPIRED = 'expired' + LOCAL_SHUTDOWN = 'local shutdown' + REMOTE_SHUTDOWN = 'remote shutdown' + RECEPTION_FAILURE = 'reception failure' + TRANSMISSION_FAILURE = 'transmission failure' + LOCAL_FAILURE = 'local failure' + REMOTE_FAILURE = 'remote failure' + + +class Completion(object): + """An aggregate of the values exchanged upon operation completion. + + Attributes: + terminal_metadata: A terminal metadata value for the operaton. + code: A code value for the operation. + message: A message value for the operation. + """ + __metaclass__ = abc.ABCMeta + + +class OperationContext(object): + """Provides operation-related information and action.""" + __metaclass__ = abc.ABCMeta + + @abc.abstractmethod + def outcome(self): + """Indicates the operation's outcome (or that the operation is ongoing). + + Returns: + None if the operation is still active or the Outcome value for the + operation if it has terminated. + """ + raise NotImplementedError() + + @abc.abstractmethod + def add_termination_callback(self, callback): + """Adds a function to be called upon operation termination. + + Args: + callback: A callable to be passed an Outcome value on operation + termination. + + Returns: + None if the operation has not yet terminated and the passed callback will + later be called when it does terminate, or if the operation has already + terminated an Outcome value describing the operation termination and the + passed callback will not be called as a result of this method call. + """ + raise NotImplementedError() + + @abc.abstractmethod + def time_remaining(self): + """Describes the length of allowed time remaining for the operation. + + Returns: + A nonnegative float indicating the length of allowed time in seconds + remaining for the operation to complete before it is considered to have + timed out. Zero is returned if the operation has terminated. + """ + raise NotImplementedError() + + @abc.abstractmethod + def cancel(self): + """Cancels the operation if the operation has not yet terminated.""" + raise NotImplementedError() + + @abc.abstractmethod + def fail(self, exception): + """Indicates that the operation has failed. + + Args: + exception: An exception germane to the operation failure. May be None. + """ + raise NotImplementedError() + + +class Operator(object): + """An interface through which to participate in an operation.""" + __metaclass__ = abc.ABCMeta + + @abc.abstractmethod + def advance( + self, initial_metadata=None, payload=None, completion=None, + allowance=None): + """Progresses the operation. + + Args: + initial_metadata: An initial metadata value. Only one may ever be + communicated in each direction for an operation, and they must be + communicated no later than either the first payload or the completion. + payload: A payload value. + completion: A Completion value. May only ever be non-None once in either + direction, and no payloads may be passed after it has been communicated. + allowance: A positive integer communicating the number of additional + payloads allowed to be passed by the remote side of the operation. + """ + raise NotImplementedError() + + +class Subscription(object): + """Describes customer code's interest in values from the other side. + + Attributes: + kind: A Kind value describing the overall kind of this value. + termination_callback: A callable to be passed the Outcome associated with + the operation after it has terminated. Must be non-None if kind is + Kind.TERMINATION_ONLY. Must be None otherwise. + allowance: A callable behavior that accepts positive integers representing + the number of additional payloads allowed to be passed to the other side + of the operation. Must be None if kind is Kind.FULL. Must not be None + otherwise. + operator: An Operator to be passed values from the other side of the + operation. Must be non-None if kind is Kind.FULL. Must be None otherwise. + """ + + @enum.unique + class Kind(enum.Enum): + + NONE = 'none' + TERMINATION_ONLY = 'termination only' + FULL = 'full' + + +class Servicer(object): + """Interface for service implementations.""" + __metaclass__ = abc.ABCMeta + + @abc.abstractmethod + def service(self, group, method, context, output_operator): + """Services an operation. + + Args: + group: The group identifier of the operation to be serviced. + method: The method identifier of the operation to be serviced. + context: An OperationContext object affording contextual information and + actions. + output_operator: An Operator that will accept output values of the + operation. + + Returns: + A Subscription via which this object may or may not accept more values of + the operation. + + Raises: + NoSuchMethodError: If this Servicer does not handle operations with the + given group and method. + abandonment.Abandoned: If the operation has been aborted and there no + longer is any reason to service the operation. + """ + raise NotImplementedError() + + +class End(object): + """Common type for entry-point objects on both sides of an operation.""" + __metaclass__ = abc.ABCMeta + + @abc.abstractmethod + def start(self): + """Starts this object's service of operations.""" + raise NotImplementedError() + + @abc.abstractmethod + def stop_gracefully(self): + """Gracefully stops this object's service of operations. + + Operations in progress will be allowed to complete, and this method blocks + until all of them have. + """ + raise NotImplementedError() + + @abc.abstractmethod + def stop_immediately(self): + """Immediately stops this object's service of operations. + + Operations in progress will not be allowed to complete. + """ + raise NotImplementedError() + + @abc.abstractmethod + def operate( + self, group, method, subscription, timeout, initial_metadata=None, + payload=None, completion=None): + """Commences an operation. + + Args: + group: The group identifier of the invoked operation. + method: The method identifier of the invoked operation. + subscription: A Subscription to which the results of the operation will be + passed. + timeout: A length of time in seconds to allow for the operation. + initial_metadata: An initial metadata value to be sent to the other side + of the operation. May be None if the initial metadata will be later + passed via the returned operator or if there will be no initial metadata + passed at all. + payload: An initial payload for the operation. + completion: A Completion value indicating the end of transmission to the + other side of the operation. + + Returns: + A pair of objects affording information about the operation and action + continuing the operation. The first element of the returned pair is an + OperationContext for the operation and the second element of the + returned pair is an Operator to which operation values not passed in + this call should later be passed. + """ + raise NotImplementedError() + + @abc.abstractmethod + def operation_stats(self): + """Reports the number of terminated operations broken down by outcome. + + Returns: + A dictionary from Outcome value to an integer identifying the number + of operations that terminated with that outcome. + """ + raise NotImplementedError() + + @abc.abstractmethod + def add_idle_action(self, action): + """Adds an action to be called when this End has no ongoing operations. + + Args: + action: A callable that accepts no arguments. + """ + raise NotImplementedError() diff --git a/src/python/grpcio/grpc/framework/interfaces/base/utilities.py b/src/python/grpcio/grpc/framework/interfaces/base/utilities.py new file mode 100644 index 0000000000..a9ee1a0981 --- /dev/null +++ b/src/python/grpcio/grpc/framework/interfaces/base/utilities.py @@ -0,0 +1,79 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Utilities for use with the base interface of RPC Framework.""" + +import collections + +from grpc.framework.interfaces.base import base + + +class _Completion( + base.Completion, + collections.namedtuple( + '_Completion', ('terminal_metadata', 'code', 'message',))): + """A trivial implementation of base.Completion.""" + + +class _Subscription( + base.Subscription, + collections.namedtuple( + '_Subscription', + ('kind', 'termination_callback', 'allowance', 'operator',))): + """A trivial implementation of base.Subscription.""" + +_NONE_SUBSCRIPTION = _Subscription( + base.Subscription.Kind.NONE, None, None, None) + + +def completion(terminal_metadata, code, message): + """Creates a base.Completion aggregating the given operation values. + + Args: + terminal_metadata: A terminal metadata value for an operaton. + code: A code value for an operation. + message: A message value for an operation. + + Returns: + A base.Completion aggregating the given operation values. + """ + return _Completion(terminal_metadata, code, message) + + +def full_subscription(operator): + """Creates a "full" base.Subscription for the given base.Operator. + + Args: + operator: A base.Operator to be used in an operation. + + Returns: + A base.Subscription of kind base.Subscription.Kind.FULL wrapping the given + base.Operator. + """ + return _Subscription(base.Subscription.Kind.FULL, None, None, operator) diff --git a/src/python/grpcio_test/grpc_test/framework/common/test_constants.py b/src/python/grpcio_test/grpc_test/framework/common/test_constants.py index 3126d0d82c..e1d3c2709d 100644 --- a/src/python/grpcio_test/grpc_test/framework/common/test_constants.py +++ b/src/python/grpcio_test/grpc_test/framework/common/test_constants.py @@ -29,15 +29,25 @@ """Constants shared among tests throughout RPC Framework.""" +# Value for maximum duration in seconds that a test is allowed for its actual +# behavioral logic, excluding all time spent deliberately waiting in the test. +TIME_ALLOWANCE = 10 # Value for maximum duration in seconds of RPCs that may time out as part of a # test. SHORT_TIMEOUT = 4 # Absurdly large value for maximum duration in seconds for should-not-time-out # RPCs made during tests. LONG_TIMEOUT = 3000 +# Values to supply on construction of an object that will service RPCs; these +# should not be used as the actual timeout values of any RPCs made during tests. +DEFAULT_TIMEOUT = 300 +MAXIMUM_TIMEOUT = 3600 # The number of payloads to transmit in streaming tests. STREAM_LENGTH = 200 +# The size of payloads to transmit in tests. +PAYLOAD_SIZE = 256 * 1024 + 17 + # The size of thread pools to use in tests. POOL_SIZE = 10 diff --git a/src/ruby/bin/interop/test/cpp/interop/empty.rb b/src/python/grpcio_test/grpc_test/framework/interfaces/base/__init__.py index 3579fa5ded..7086519106 100644 --- a/src/ruby/bin/interop/test/cpp/interop/empty.rb +++ b/src/python/grpcio_test/grpc_test/framework/interfaces/base/__init__.py @@ -27,18 +27,4 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: test/cpp/interop/empty.proto -require 'google/protobuf' - -Google::Protobuf::DescriptorPool.generated_pool.build do - add_message "grpc.testing.Empty" do - end -end - -module Grpc - module Testing - Empty = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Empty").msgclass - end -end diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py b/src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py new file mode 100644 index 0000000000..e4d2a7a0d7 --- /dev/null +++ b/src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py @@ -0,0 +1,568 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Part of the tests of the base interface of RPC Framework.""" + +import abc +import collections +import enum +import random # pylint: disable=unused-import +import threading +import time + +from grpc.framework.interfaces.base import base +from grpc_test.framework.common import test_constants +from grpc_test.framework.interfaces.base import _sequence +from grpc_test.framework.interfaces.base import _state +from grpc_test.framework.interfaces.base import test_interfaces # pylint: disable=unused-import + +_GROUP = 'base test cases test group' +_METHOD = 'base test cases test method' + +_PAYLOAD_RANDOM_SECTION_MAXIMUM_SIZE = test_constants.PAYLOAD_SIZE / 20 +_MINIMUM_PAYLOAD_SIZE = test_constants.PAYLOAD_SIZE / 600 + + +def _create_payload(randomness): + length = randomness.randint( + _MINIMUM_PAYLOAD_SIZE, test_constants.PAYLOAD_SIZE) + random_section_length = randomness.randint( + 0, min(_PAYLOAD_RANDOM_SECTION_MAXIMUM_SIZE, length)) + random_section = bytes( + bytearray( + randomness.getrandbits(8) for _ in range(random_section_length))) + sevens_section = '\x07' * (length - random_section_length) + return b''.join(randomness.sample((random_section, sevens_section), 2)) + + +def _anything_in_flight(state): + return ( + state.invocation_initial_metadata_in_flight is not None or + state.invocation_payloads_in_flight or + state.invocation_completion_in_flight is not None or + state.service_initial_metadata_in_flight is not None or + state.service_payloads_in_flight or + state.service_completion_in_flight is not None or + 0 < state.invocation_allowance_in_flight or + 0 < state.service_allowance_in_flight + ) + + +def _verify_service_advance_and_update_state( + initial_metadata, payload, completion, allowance, state, implementation): + if initial_metadata is not None: + if state.invocation_initial_metadata_received: + return 'Later invocation initial metadata received: %s' % ( + initial_metadata,) + if state.invocation_payloads_received: + return 'Invocation initial metadata received after payloads: %s' % ( + state.invocation_payloads_received) + if state.invocation_completion_received: + return 'Invocation initial metadata received after invocation completion!' + if not implementation.metadata_transmitted( + state.invocation_initial_metadata_in_flight, initial_metadata): + return 'Invocation initial metadata maltransmitted: %s, %s' % ( + state.invocation_initial_metadata_in_flight, initial_metadata) + else: + state.invocation_initial_metadata_in_flight = None + state.invocation_initial_metadata_received = True + + if payload is not None: + if state.invocation_completion_received: + return 'Invocation payload received after invocation completion!' + elif not state.invocation_payloads_in_flight: + return 'Invocation payload "%s" received but not in flight!' % (payload,) + elif state.invocation_payloads_in_flight[0] != payload: + return 'Invocation payload mismatch: %s, %s' % ( + state.invocation_payloads_in_flight[0], payload) + elif state.service_side_invocation_allowance < 1: + return 'Disallowed invocation payload!' + else: + state.invocation_payloads_in_flight.pop(0) + state.invocation_payloads_received += 1 + state.service_side_invocation_allowance -= 1 + + if completion is not None: + if state.invocation_completion_received: + return 'Later invocation completion received: %s' % (completion,) + elif not implementation.completion_transmitted( + state.invocation_completion_in_flight, completion): + return 'Invocation completion maltransmitted: %s, %s' % ( + state.invocation_completion_in_flight, completion) + else: + state.invocation_completion_in_flight = None + state.invocation_completion_received = True + + if allowance is not None: + if allowance <= 0: + return 'Illegal allowance value: %s' % (allowance,) + else: + state.service_allowance_in_flight -= allowance + state.service_side_service_allowance += allowance + + +def _verify_invocation_advance_and_update_state( + initial_metadata, payload, completion, allowance, state, implementation): + if initial_metadata is not None: + if state.service_initial_metadata_received: + return 'Later service initial metadata received: %s' % (initial_metadata,) + if state.service_payloads_received: + return 'Service initial metadata received after service payloads: %s' % ( + state.service_payloads_received) + if state.service_completion_received: + return 'Service initial metadata received after service completion!' + if not implementation.metadata_transmitted( + state.service_initial_metadata_in_flight, initial_metadata): + return 'Service initial metadata maltransmitted: %s, %s' % ( + state.service_initial_metadata_in_flight, initial_metadata) + else: + state.service_initial_metadata_in_flight = None + state.service_initial_metadata_received = True + + if payload is not None: + if state.service_completion_received: + return 'Service payload received after service completion!' + elif not state.service_payloads_in_flight: + return 'Service payload "%s" received but not in flight!' % (payload,) + elif state.service_payloads_in_flight[0] != payload: + return 'Service payload mismatch: %s, %s' % ( + state.invocation_payloads_in_flight[0], payload) + elif state.invocation_side_service_allowance < 1: + return 'Disallowed service payload!' + else: + state.service_payloads_in_flight.pop(0) + state.service_payloads_received += 1 + state.invocation_side_service_allowance -= 1 + + if completion is not None: + if state.service_completion_received: + return 'Later service completion received: %s' % (completion,) + elif not implementation.completion_transmitted( + state.service_completion_in_flight, completion): + return 'Service completion maltransmitted: %s, %s' % ( + state.service_completion_in_flight, completion) + else: + state.service_completion_in_flight = None + state.service_completion_received = True + + if allowance is not None: + if allowance <= 0: + return 'Illegal allowance value: %s' % (allowance,) + else: + state.invocation_allowance_in_flight -= allowance + state.invocation_side_service_allowance += allowance + + +class Invocation( + collections.namedtuple( + 'Invocation', + ('group', 'method', 'subscription_kind', 'timeout', 'initial_metadata', + 'payload', 'completion',))): + """A description of operation invocation. + + Attributes: + group: The group identifier for the operation. + method: The method identifier for the operation. + subscription_kind: A base.Subscription.Kind value describing the kind of + subscription to use for the operation. + timeout: A duration in seconds to pass as the timeout value for the + operation. + initial_metadata: An object to pass as the initial metadata for the + operation or None. + payload: An object to pass as a payload value for the operation or None. + completion: An object to pass as a completion value for the operation or + None. + """ + + +class OnAdvance( + collections.namedtuple( + 'OnAdvance', + ('kind', 'initial_metadata', 'payload', 'completion', 'allowance'))): + """Describes action to be taken in a test in response to an advance call. + + Attributes: + kind: A Kind value describing the overall kind of response. + initial_metadata: An initial metadata value to pass to a call of the advance + method of the operator under test. Only valid if kind is Kind.ADVANCE and + may be None. + payload: A payload value to pass to a call of the advance method of the + operator under test. Only valid if kind is Kind.ADVANCE and may be None. + completion: A base.Completion value to pass to a call of the advance method + of the operator under test. Only valid if kind is Kind.ADVANCE and may be + None. + allowance: An allowance value to pass to a call of the advance method of the + operator under test. Only valid if kind is Kind.ADVANCE and may be None. + """ + + @enum.unique + class Kind(enum.Enum): + ADVANCE = 'advance' + DEFECT = 'defect' + IDLE = 'idle' + + +_DEFECT_ON_ADVANCE = OnAdvance(OnAdvance.Kind.DEFECT, None, None, None, None) +_IDLE_ON_ADVANCE = OnAdvance(OnAdvance.Kind.IDLE, None, None, None, None) + + +class Instruction( + collections.namedtuple( + 'Instruction', + ('kind', 'advance_args', 'advance_kwargs', 'conclude_success', + 'conclude_message', 'conclude_invocation_outcome', + 'conclude_service_outcome',))): + """""" + + @enum.unique + class Kind(enum.Enum): + ADVANCE = 'ADVANCE' + CANCEL = 'CANCEL' + CONCLUDE = 'CONCLUDE' + + +class Controller(object): + __metaclass__ = abc.ABCMeta + + @abc.abstractmethod + def failed(self, message): + """""" + raise NotImplementedError() + + @abc.abstractmethod + def serialize_request(self, request): + """""" + raise NotImplementedError() + + @abc.abstractmethod + def deserialize_request(self, serialized_request): + """""" + raise NotImplementedError() + + @abc.abstractmethod + def serialize_response(self, response): + """""" + raise NotImplementedError() + + @abc.abstractmethod + def deserialize_response(self, serialized_response): + """""" + raise NotImplementedError() + + @abc.abstractmethod + def invocation(self): + """""" + raise NotImplementedError() + + @abc.abstractmethod + def poll(self): + """""" + raise NotImplementedError() + + @abc.abstractmethod + def on_service_advance( + self, initial_metadata, payload, completion, allowance): + """""" + raise NotImplementedError() + + @abc.abstractmethod + def on_invocation_advance( + self, initial_metadata, payload, completion, allowance): + """""" + raise NotImplementedError() + + @abc.abstractmethod + def service_on_termination(self, outcome): + """""" + raise NotImplementedError() + + @abc.abstractmethod + def invocation_on_termination(self, outcome): + """""" + raise NotImplementedError() + + +class ControllerCreator(object): + __metaclass__ = abc.ABCMeta + + @abc.abstractmethod + def name(self): + """""" + raise NotImplementedError() + + @abc.abstractmethod + def controller(self, implementation, randomness): + """""" + raise NotImplementedError() + + +class _Remainder( + collections.namedtuple( + '_Remainder', + ('invocation_payloads', 'service_payloads', 'invocation_completion', + 'service_completion',))): + """Describes work remaining to be done in a portion of a test. + + Attributes: + invocation_payloads: The number of payloads to be sent from the invocation + side of the operation to the service side of the operation. + service_payloads: The number of payloads to be sent from the service side of + the operation to the invocation side of the operation. + invocation_completion: Whether or not completion from the invocation side of + the operation should be indicated and has yet to be indicated. + service_completion: Whether or not completion from the service side of the + operation should be indicated and has yet to be indicated. + """ + + +class _SequenceController(Controller): + + def __init__(self, sequence, implementation, randomness): + """Constructor. + + Args: + sequence: A _sequence.Sequence describing the steps to be taken in the + test at a relatively high level. + implementation: A test_interfaces.Implementation encapsulating the + base interface implementation that is the system under test. + randomness: A random.Random instance for use in the test. + """ + self._condition = threading.Condition() + self._sequence = sequence + self._implementation = implementation + self._randomness = randomness + + self._until = None + self._remaining_elements = None + self._poll_next = None + self._message = None + + self._state = _state.OperationState() + self._todo = None + + # called with self._condition + def _failed(self, message): + self._message = message + self._condition.notify_all() + + def _passed(self, invocation_outcome, service_outcome): + self._poll_next = Instruction( + Instruction.Kind.CONCLUDE, None, None, True, None, invocation_outcome, + service_outcome) + self._condition.notify_all() + + def failed(self, message): + with self._condition: + self._failed(message) + + def serialize_request(self, request): + return request + request + + def deserialize_request(self, serialized_request): + return serialized_request[:len(serialized_request) / 2] + + def serialize_response(self, response): + return response * 3 + + def deserialize_response(self, serialized_response): + return serialized_response[2 * len(serialized_response) / 3:] + + def invocation(self): + with self._condition: + self._until = time.time() + self._sequence.maximum_duration + self._remaining_elements = list(self._sequence.elements) + if self._sequence.invocation.initial_metadata: + initial_metadata = self._implementation.invocation_initial_metadata() + self._state.invocation_initial_metadata_in_flight = initial_metadata + else: + initial_metadata = None + if self._sequence.invocation.payload: + payload = _create_payload(self._randomness) + self._state.invocation_payloads_in_flight.append(payload) + else: + payload = None + if self._sequence.invocation.complete: + completion = self._implementation.invocation_completion() + self._state.invocation_completion_in_flight = completion + else: + completion = None + return Invocation( + _GROUP, _METHOD, base.Subscription.Kind.FULL, + self._sequence.invocation.timeout, initial_metadata, payload, + completion) + + def poll(self): + with self._condition: + while True: + if self._message is not None: + return Instruction( + Instruction.Kind.CONCLUDE, None, None, False, self._message, None, + None) + elif self._poll_next: + poll_next = self._poll_next + self._poll_next = None + return poll_next + elif self._until < time.time(): + return Instruction( + Instruction.Kind.CONCLUDE, None, None, False, + 'overran allotted time!', None, None) + else: + self._condition.wait(timeout=self._until-time.time()) + + def on_service_advance( + self, initial_metadata, payload, completion, allowance): + with self._condition: + message = _verify_service_advance_and_update_state( + initial_metadata, payload, completion, allowance, self._state, + self._implementation) + if message is not None: + self._failed(message) + if self._todo is not None: + raise ValueError('TODO!!!') + elif _anything_in_flight(self._state): + return _IDLE_ON_ADVANCE + elif self._remaining_elements: + element = self._remaining_elements.pop(0) + if element.kind is _sequence.Element.Kind.SERVICE_TRANSMISSION: + if element.transmission.initial_metadata: + initial_metadata = self._implementation.service_initial_metadata() + self._state.service_initial_metadata_in_flight = initial_metadata + else: + initial_metadata = None + if element.transmission.payload: + payload = _create_payload(self._randomness) + self._state.service_payloads_in_flight.append(payload) + self._state.service_side_service_allowance -= 1 + else: + payload = None + if element.transmission.complete: + completion = self._implementation.service_completion() + self._state.service_completion_in_flight = completion + else: + completion = None + if (not self._state.invocation_completion_received and + 0 <= self._state.service_side_invocation_allowance): + allowance = 1 + self._state.service_side_invocation_allowance += 1 + self._state.invocation_allowance_in_flight += 1 + else: + allowance = None + return OnAdvance( + OnAdvance.Kind.ADVANCE, initial_metadata, payload, completion, + allowance) + else: + raise ValueError('TODO!!!') + else: + return _IDLE_ON_ADVANCE + + def on_invocation_advance( + self, initial_metadata, payload, completion, allowance): + with self._condition: + message = _verify_invocation_advance_and_update_state( + initial_metadata, payload, completion, allowance, self._state, + self._implementation) + if message is not None: + self._failed(message) + if self._todo is not None: + raise ValueError('TODO!!!') + elif _anything_in_flight(self._state): + return _IDLE_ON_ADVANCE + elif self._remaining_elements: + element = self._remaining_elements.pop(0) + if element.kind is _sequence.Element.Kind.INVOCATION_TRANSMISSION: + if element.transmission.initial_metadata: + initial_metadata = self._implementation.invocation_initial_metadata() + self._state.invocation_initial_metadata_in_fight = initial_metadata + else: + initial_metadata = None + if element.transmission.payload: + payload = _create_payload(self._randomness) + self._state.invocation_payloads_in_flight.append(payload) + self._state.invocation_side_invocation_allowance -= 1 + else: + payload = None + if element.transmission.complete: + completion = self._implementation.invocation_completion() + self._state.invocation_completion_in_flight = completion + else: + completion = None + if (not self._state.service_completion_received and + 0 <= self._state.invocation_side_service_allowance): + allowance = 1 + self._state.invocation_side_service_allowance += 1 + self._state.service_allowance_in_flight += 1 + else: + allowance = None + return OnAdvance( + OnAdvance.Kind.ADVANCE, initial_metadata, payload, completion, + allowance) + else: + raise ValueError('TODO!!!') + else: + return _IDLE_ON_ADVANCE + + def service_on_termination(self, outcome): + with self._condition: + self._state.service_side_outcome = outcome + if self._todo is not None or self._remaining_elements: + self._failed('Premature service-side outcome %s!' % (outcome,)) + elif outcome is not self._sequence.outcome.service: + self._failed( + 'Incorrect service-side outcome: %s should have been %s' % ( + outcome, self._sequence.outcome.service)) + elif self._state.invocation_side_outcome is not None: + self._passed(self._state.invocation_side_outcome, outcome) + + def invocation_on_termination(self, outcome): + with self._condition: + self._state.invocation_side_outcome = outcome + if self._todo is not None or self._remaining_elements: + self._failed('Premature invocation-side outcome %s!' % (outcome,)) + elif outcome is not self._sequence.outcome.invocation: + self._failed( + 'Incorrect invocation-side outcome: %s should have been %s' % ( + outcome, self._sequence.outcome.invocation)) + elif self._state.service_side_outcome is not None: + self._passed(outcome, self._state.service_side_outcome) + + +class _SequenceControllerCreator(ControllerCreator): + + def __init__(self, sequence): + self._sequence = sequence + + def name(self): + return self._sequence.name + + def controller(self, implementation, randomness): + return _SequenceController(self._sequence, implementation, randomness) + + +CONTROLLER_CREATORS = tuple( + _SequenceControllerCreator(sequence) for sequence in _sequence.SEQUENCES) diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py b/src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py new file mode 100644 index 0000000000..1d77aaebe6 --- /dev/null +++ b/src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py @@ -0,0 +1,168 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Part of the tests of the base interface of RPC Framework.""" + +import collections +import enum + +from grpc.framework.interfaces.base import base +from grpc_test.framework.common import test_constants + + +class Invocation( + collections.namedtuple( + 'Invocation', ('timeout', 'initial_metadata', 'payload', 'complete',))): + """A recipe for operation invocation. + + Attributes: + timeout: A duration in seconds to pass to the system under test as the + operation's timeout value. + initial_metadata: A boolean indicating whether or not to pass initial + metadata when invoking the operation. + payload: A boolean indicating whether or not to pass a payload when + invoking the operation. + complete: A boolean indicating whether or not to indicate completion of + transmissions from the invoking side of the operation when invoking the + operation. + """ + + +class Transmission( + collections.namedtuple( + 'Transmission', ('initial_metadata', 'payload', 'complete',))): + """A recipe for a single transmission in an operation. + + Attributes: + initial_metadata: A boolean indicating whether or not to pass initial + metadata as part of the transmission. + payload: A boolean indicating whether or not to pass a payload as part of + the transmission. + complete: A boolean indicating whether or not to indicate completion of + transmission from the transmitting side of the operation as part of the + transmission. + """ + + +class Intertransmission( + collections.namedtuple('Intertransmission', ('invocation', 'service',))): + """A recipe for multiple transmissions in an operation. + + Attributes: + invocation: An integer describing the number of payloads to send from the + invocation side of the operation to the service side. + service: An integer describing the number of payloads to send from the + service side of the operation to the invocation side. + """ + + +class Element(collections.namedtuple('Element', ('kind', 'transmission',))): + """A sum type for steps to perform when testing an operation. + + Attributes: + kind: A Kind value describing the kind of step to perform in the test. + transmission: Only valid for kinds Kind.INVOCATION_TRANSMISSION and + Kind.SERVICE_TRANSMISSION, a Transmission value describing the details of + the transmission to be made. + """ + + @enum.unique + class Kind(enum.Enum): + INVOCATION_TRANSMISSION = 'invocation transmission' + SERVICE_TRANSMISSION = 'service transmission' + INTERTRANSMISSION = 'intertransmission' + INVOCATION_CANCEL = 'invocation cancel' + SERVICE_CANCEL = 'service cancel' + INVOCATION_FAILURE = 'invocation failure' + SERVICE_FAILURE = 'service failure' + + +class Outcome(collections.namedtuple('Outcome', ('invocation', 'service',))): + """A description of the expected outcome of an operation test. + + Attributes: + invocation: The base.Outcome value expected on the invocation side of the + operation. + service: The base.Outcome value expected on the service side of the + operation. + """ + + +class Sequence( + collections.namedtuple( + 'Sequence', + ('name', 'maximum_duration', 'invocation', 'elements', 'outcome',))): + """Describes at a high level steps to perform in a test. + + Attributes: + name: The string name of the sequence. + maximum_duration: A length of time in seconds to allow for the test before + declaring it to have failed. + invocation: An Invocation value describing how to invoke the operation + under test. + elements: A sequence of Element values describing at coarse granularity + actions to take during the operation under test. + outcome: An Outcome value describing the expected outcome of the test. + """ + +_EASY = Sequence( + 'Easy', + test_constants.TIME_ALLOWANCE, + Invocation(test_constants.LONG_TIMEOUT, True, True, True), + ( + Element( + Element.Kind.SERVICE_TRANSMISSION, Transmission(True, True, True)), + ), + Outcome(base.Outcome.COMPLETED, base.Outcome.COMPLETED)) + +_PEASY = Sequence( + 'Peasy', + test_constants.TIME_ALLOWANCE, + Invocation(test_constants.LONG_TIMEOUT, True, True, False), + ( + Element( + Element.Kind.SERVICE_TRANSMISSION, Transmission(True, True, False)), + Element( + Element.Kind.INVOCATION_TRANSMISSION, + Transmission(False, True, True)), + Element( + Element.Kind.SERVICE_TRANSMISSION, Transmission(False, True, True)), + ), + Outcome(base.Outcome.COMPLETED, base.Outcome.COMPLETED)) + + +# TODO(issue 2959): Finish this test suite. This tuple of sequences should +# contain at least the values in the Cartesian product of (half-duplex, +# full-duplex) * (zero payloads, one payload, test_constants.STREAM_LENGTH +# payloads) * (completion, cancellation, expiration, programming defect in +# servicer code). +SEQUENCES = ( + _EASY, + _PEASY, +) diff --git a/src/ruby/bin/interop/test/cpp/interop/test_services.rb b/src/python/grpcio_test/grpc_test/framework/interfaces/base/_state.py index 5a3146c581..21cf33aeb6 100644 --- a/src/ruby/bin/interop/test/cpp/interop/test_services.rb +++ b/src/python/grpcio_test/grpc_test/framework/interfaces/base/_state.py @@ -27,34 +27,29 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# Generated by the protocol buffer compiler. DO NOT EDIT! -# Source: test/cpp/interop/test.proto for package 'grpc.testing' - -require 'grpc' -require 'test/cpp/interop/test' - -module Grpc - module Testing - module TestService - - # TODO: add proto service documentation here - class Service - - include GRPC::GenericService - - self.marshal_class_method = :encode - self.unmarshal_class_method = :decode - self.service_name = 'grpc.testing.TestService' - - rpc :EmptyCall, Empty, Empty - rpc :UnaryCall, SimpleRequest, SimpleResponse - rpc :StreamingOutputCall, StreamingOutputCallRequest, stream(StreamingOutputCallResponse) - rpc :StreamingInputCall, stream(StreamingInputCallRequest), StreamingInputCallResponse - rpc :FullDuplexCall, stream(StreamingOutputCallRequest), stream(StreamingOutputCallResponse) - rpc :HalfDuplexCall, stream(StreamingOutputCallRequest), stream(StreamingOutputCallResponse) - end - - Stub = Service.rpc_stub_class - end - end -end +"""Part of the tests of the base interface of RPC Framework.""" + + +class OperationState(object): + + def __init__(self): + self.invocation_initial_metadata_in_flight = None + self.invocation_initial_metadata_received = False + self.invocation_payloads_in_flight = [] + self.invocation_payloads_received = 0 + self.invocation_completion_in_flight = None + self.invocation_completion_received = False + self.service_initial_metadata_in_flight = None + self.service_initial_metadata_received = False + self.service_payloads_in_flight = [] + self.service_payloads_received = 0 + self.service_completion_in_flight = None + self.service_completion_received = False + self.invocation_side_invocation_allowance = 1 + self.invocation_side_service_allowance = 1 + self.service_side_invocation_allowance = 1 + self.service_side_service_allowance = 1 + self.invocation_allowance_in_flight = 0 + self.service_allowance_in_flight = 0 + self.invocation_side_outcome = None + self.service_side_outcome = None diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py b/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py new file mode 100644 index 0000000000..dd332fe5dd --- /dev/null +++ b/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py @@ -0,0 +1,260 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Tests of the base interface of RPC Framework.""" + +import logging +import random +import threading +import time +import unittest + +from grpc.framework.foundation import logging_pool +from grpc.framework.interfaces.base import base +from grpc.framework.interfaces.base import utilities +from grpc_test.framework.common import test_constants +from grpc_test.framework.interfaces.base import _control +from grpc_test.framework.interfaces.base import test_interfaces + +_SYNCHRONICITY_VARIATION = (('Sync', False), ('Async', True)) + +_EMPTY_OUTCOME_DICT = {outcome: 0 for outcome in base.Outcome} + + +class _Serialization(test_interfaces.Serialization): + + def serialize_request(self, request): + return request + request + + def deserialize_request(self, serialized_request): + return serialized_request[:len(serialized_request) / 2] + + def serialize_response(self, response): + return response * 3 + + def deserialize_response(self, serialized_response): + return serialized_response[2 * len(serialized_response) / 3:] + + +def _advance(quadruples, operator, controller): + try: + for quadruple in quadruples: + operator.advance( + initial_metadata=quadruple[0], payload=quadruple[1], + completion=quadruple[2], allowance=quadruple[3]) + except Exception as e: # pylint: disable=broad-except + controller.failed('Exception on advance: %e' % e) + + +class _Operator(base.Operator): + + def __init__(self, controller, on_advance, pool, operator_under_test): + self._condition = threading.Condition() + self._controller = controller + self._on_advance = on_advance + self._pool = pool + self._operator_under_test = operator_under_test + self._pending_advances = [] + + def set_operator_under_test(self, operator_under_test): + with self._condition: + self._operator_under_test = operator_under_test + pent_advances = self._pending_advances + self._pending_advances = [] + pool = self._pool + controller = self._controller + + if pool is None: + _advance(pent_advances, operator_under_test, controller) + else: + pool.submit(_advance, pent_advances, operator_under_test, controller) + + def advance( + self, initial_metadata=None, payload=None, completion=None, + allowance=None): + on_advance = self._on_advance( + initial_metadata, payload, completion, allowance) + if on_advance.kind is _control.OnAdvance.Kind.ADVANCE: + with self._condition: + pool = self._pool + operator_under_test = self._operator_under_test + controller = self._controller + + quadruple = ( + on_advance.initial_metadata, on_advance.payload, + on_advance.completion, on_advance.allowance) + if pool is None: + _advance((quadruple,), operator_under_test, controller) + else: + pool.submit(_advance, (quadruple,), operator_under_test, controller) + elif on_advance.kind is _control.OnAdvance.Kind.DEFECT: + raise ValueError( + 'Deliberately raised exception from Operator.advance (in a test)!') + + +class _Servicer(base.Servicer): + """An base.Servicer with instrumented for testing.""" + + def __init__(self, group, method, controllers, pool): + self._condition = threading.Condition() + self._group = group + self._method = method + self._pool = pool + self._controllers = list(controllers) + + def service(self, group, method, context, output_operator): + with self._condition: + controller = self._controllers.pop(0) + if group != self._group or method != self._method: + controller.fail( + '%s != %s or %s != %s' % (group, self._group, method, self._method)) + raise base.NoSuchMethodError() + else: + operator = _Operator( + controller, controller.on_service_advance, self._pool, + output_operator) + outcome = context.add_termination_callback( + controller.service_on_termination) + if outcome is not None: + controller.service_on_termination(outcome) + return utilities.full_subscription(operator) + + +class _OperationTest(unittest.TestCase): + + def setUp(self): + if self._synchronicity_variation: + self._pool = logging_pool.pool(test_constants.POOL_SIZE) + else: + self._pool = None + self._controller = self._controller_creator.controller( + self._implementation, self._randomness) + + def tearDown(self): + if self._synchronicity_variation: + self._pool.shutdown(wait=True) + else: + self._pool = None + + def test_operation(self): + invocation = self._controller.invocation() + if invocation.subscription_kind is base.Subscription.Kind.FULL: + test_operator = _Operator( + self._controller, self._controller.on_invocation_advance, + self._pool, None) + subscription = utilities.full_subscription(test_operator) + else: + # TODO(nathaniel): support and test other subscription kinds. + self.fail('Non-full subscriptions not yet supported!') + + servicer = _Servicer( + invocation.group, invocation.method, (self._controller,), self._pool) + + invocation_end, service_end, memo = self._implementation.instantiate( + {(invocation.group, invocation.method): _Serialization()}, servicer) + + try: + invocation_end.start() + service_end.start() + operation_context, operator_under_test = invocation_end.operate( + invocation.group, invocation.method, subscription, invocation.timeout, + initial_metadata=invocation.initial_metadata, payload=invocation.payload, + completion=invocation.completion) + test_operator.set_operator_under_test(operator_under_test) + outcome = operation_context.add_termination_callback( + self._controller.invocation_on_termination) + if outcome is not None: + self._controller.invocation_on_termination(outcome) + except Exception as e: # pylint: disable=broad-except + self._controller.failed('Exception on invocation: %s' % e) + self.fail(e) + + while True: + instruction = self._controller.poll() + if instruction.kind is _control.Instruction.Kind.ADVANCE: + try: + test_operator.advance( + *instruction.advance_args, **instruction.advance_kwargs) + except Exception as e: # pylint: disable=broad-except + self._controller.failed('Exception on instructed advance: %s' % e) + elif instruction.kind is _control.Instruction.Kind.CANCEL: + try: + operation_context.cancel() + except Exception as e: # pylint: disable=broad-except + self._controller.failed('Exception on cancel: %s' % e) + elif instruction.kind is _control.Instruction.Kind.CONCLUDE: + break + + invocation_end.stop_gracefully() + service_end.stop_gracefully() + invocation_stats = invocation_end.operation_stats() + service_stats = service_end.operation_stats() + + self._implementation.destantiate(memo) + + self.assertTrue( + instruction.conclude_success, msg=instruction.conclude_message) + + expected_invocation_stats = dict(_EMPTY_OUTCOME_DICT) + expected_invocation_stats[instruction.conclude_invocation_outcome] += 1 + self.assertDictEqual(expected_invocation_stats, invocation_stats) + expected_service_stats = dict(_EMPTY_OUTCOME_DICT) + expected_service_stats[instruction.conclude_service_outcome] += 1 + self.assertDictEqual(expected_service_stats, service_stats) + + +def test_cases(implementation): + """Creates unittest.TestCase classes for a given Base implementation. + + Args: + implementation: A test_interfaces.Implementation specifying creation and + destruction of the Base implementation under test. + + Returns: + A sequence of subclasses of unittest.TestCase defining tests of the + specified Base layer implementation. + """ + random_seed = hash(time.time()) + logging.warning('Random seed for this execution: %s', random_seed) + randomness = random.Random(x=random_seed) + + test_case_classes = [] + for synchronicity_variation in _SYNCHRONICITY_VARIATION: + for controller_creator in _control.CONTROLLER_CREATORS: + name = ''.join( + (synchronicity_variation[0], controller_creator.name(), 'Test',)) + test_case_classes.append( + type(name, (_OperationTest,), + {'_implementation': implementation, + '_randomness': randomness, + '_synchronicity_variation': synchronicity_variation[1], + '_controller_creator': controller_creator, + })) + + return test_case_classes diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_interfaces.py b/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_interfaces.py new file mode 100644 index 0000000000..02426ab846 --- /dev/null +++ b/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_interfaces.py @@ -0,0 +1,186 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Interfaces used in tests of implementations of the Base layer.""" + +import abc + +from grpc.framework.interfaces.base import base # pylint: disable=unused-import + + +class Serialization(object): + """Specifies serialization and deserialization of test payloads.""" + __metaclass__ = abc.ABCMeta + + def serialize_request(self, request): + """Serializes a request value used in a test. + + Args: + request: A request value created by a test. + + Returns: + A bytestring that is the serialization of the given request. + """ + raise NotImplementedError() + + def deserialize_request(self, serialized_request): + """Deserializes a request value used in a test. + + Args: + serialized_request: A bytestring that is the serialization of some request + used in a test. + + Returns: + The request value encoded by the given bytestring. + """ + raise NotImplementedError() + + def serialize_response(self, response): + """Serializes a response value used in a test. + + Args: + response: A response value created by a test. + + Returns: + A bytestring that is the serialization of the given response. + """ + raise NotImplementedError() + + def deserialize_response(self, serialized_response): + """Deserializes a response value used in a test. + + Args: + serialized_response: A bytestring that is the serialization of some + response used in a test. + + Returns: + The response value encoded by the given bytestring. + """ + raise NotImplementedError() + + +class Implementation(object): + """Specifies an implementation of the Base layer.""" + __metaclass__ = abc.ABCMeta + + @abc.abstractmethod + def instantiate(self, serializations, servicer): + """Instantiates the Base layer implementation to be used in a test. + + Args: + serializations: A dict from group-method pair to Serialization object + specifying how to serialize and deserialize payload values used in the + test. + servicer: A base.Servicer object to be called to service RPCs made during + the test. + + Returns: + A sequence of length three the first element of which is a + base.End to be used to invoke RPCs, the second element of which is a + base.End to be used to service invoked RPCs, and the third element of + which is an arbitrary memo object to be kept and passed to destantiate + at the conclusion of the test. + """ + raise NotImplementedError() + + @abc.abstractmethod + def destantiate(self, memo): + """Destroys the Base layer implementation under test. + + Args: + memo: The object from the third position of the return value of a call to + instantiate. + """ + raise NotImplementedError() + + @abc.abstractmethod + def invocation_initial_metadata(self): + """Provides an operation's invocation-side initial metadata. + + Returns: + A value to use for an operation's invocation-side initial metadata, or + None. + """ + raise NotImplementedError() + + @abc.abstractmethod + def service_initial_metadata(self): + """Provices an operation's service-side initial metadata. + + Returns: + A value to use for an operation's service-side initial metadata, or + None. + """ + raise NotImplementedError() + + @abc.abstractmethod + def invocation_completion(self): + """Provides an operation's invocation-side completion. + + Returns: + A base.Completion to use for an operation's invocation-side completion. + """ + raise NotImplementedError() + + @abc.abstractmethod + def service_completion(self): + """Provides an operation's service-side completion. + + Returns: + A base.Completion to use for an operation's service-side completion. + """ + raise NotImplementedError() + + @abc.abstractmethod + def metadata_transmitted(self, original_metadata, transmitted_metadata): + """Identifies whether or not metadata was properly transmitted. + + Args: + original_metadata: A metadata value passed to the system under test. + transmitted_metadata: The same metadata value after having been + transmitted through the system under test. + + Returns: + Whether or not the metadata was properly transmitted. + """ + raise NotImplementedError() + + @abc.abstractmethod + def completion_transmitted(self, original_completion, transmitted_completion): + """Identifies whether or not a base.Completion was properly transmitted. + + Args: + original_completion: A base.Completion passed to the system under test. + transmitted_completion: The same completion value after having been + transmitted through the system under test. + + Returns: + Whether or not the completion was properly transmitted. + """ + raise NotImplementedError() diff --git a/src/ruby/.rspec b/src/ruby/.rspec index cd7c5fb5b2..2320752db4 100755 --- a/src/ruby/.rspec +++ b/src/ruby/.rspec @@ -1,4 +1,5 @@ -I. +-Ipb --require spec_helper --format documentation --color diff --git a/src/ruby/.rubocop.yml b/src/ruby/.rubocop.yml index 47e382afa7..312bdca384 100644 --- a/src/ruby/.rubocop.yml +++ b/src/ruby/.rubocop.yml @@ -5,6 +5,7 @@ inherit_from: .rubocop_todo.yml AllCops: Exclude: - 'bin/apis/**/*' - - 'bin/interop/test/**/*' - 'bin/math.rb' - 'bin/math_services.rb' + - 'pb/grpc/health/v1alpha/*' + - 'pb/test/**/*' diff --git a/src/ruby/README.md b/src/ruby/README.md index 4b657c0bd4..f8902e34c5 100644 --- a/src/ruby/README.md +++ b/src/ruby/README.md @@ -12,12 +12,36 @@ PREREQUISITES ------------- - Ruby 2.x. The gRPC API uses keyword args. -- [homebrew][] on Mac OS X, [linuxbrew][] on Linux. These simplify the installation of the gRPC C core. +- [homebrew][] on Mac OS X. These simplify the installation of the gRPC C core. INSTALLATION --------------- -On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][]. -Run the following command to install gRPC Ruby. + +**Linux (Debian):** + +Add [Debian unstable][] to your `sources.list` file. Example: + +```sh +echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" | \ +sudo tee -a /etc/apt/sources.list +``` + +Install the gRPC Debian package + +```sh +sudo apt-get update +sudo apt-get install libgrpc-dev +``` + +Install the gRPC Ruby package + +```sh +gem install grpc +``` + +**Mac OS X** + +Install [homebrew][]. Run the following command to install gRPC Ruby. ```sh $ curl -fsSL https://goo.gl/getgrpc | bash -s ruby ``` @@ -26,12 +50,6 @@ This will download and run the [gRPC install script][], then install the latest BUILD FROM SOURCE --------------------- - Clone this repository -- Build the gRPC C core -E.g, from the root of the gRPC [Git repository](https://github.com/google/grpc) -```sh -$ 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. @@ -77,8 +95,8 @@ Directory structure is the layout for [ruby extensions][] GRPC.logger.info("Answer: #{resp.inspect}") ``` [homebrew]:http://brew.sh -[linuxbrew]:https://github.com/Homebrew/linuxbrew#installation [gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install [ruby extensions]:http://guides.rubygems.org/gems-with-extensions/ [rubydoc]: http://www.rubydoc.info/gems/grpc [grpc.io]: http://www.grpc.io/docs/installation/ruby.html +[Debian unstable]:https://www.debian.org/releases/sid/ diff --git a/src/ruby/Rakefile b/src/ruby/Rakefile index 02af9a84b8..cc7832b12d 100755 --- a/src/ruby/Rakefile +++ b/src/ruby/Rakefile @@ -20,7 +20,8 @@ SPEC_SUITES = [ { id: :bidi, title: 'bidi tests', dir: %w(spec/generic), tag: 'bidi' }, { id: :server, title: 'rpc server thread tests', dir: %w(spec/generic), - tag: 'server' } + tag: 'server' }, + { id: :pb, title: 'protobuf service tests', dir: %w(spec/pb) } ] namespace :suite do SPEC_SUITES.each do |suite| @@ -50,7 +51,8 @@ task 'suite:wrapper' => [:compile, :rubocop] task 'suite:idiomatic' => 'suite:wrapper' task 'suite:bidi' => 'suite:wrapper' task 'suite:server' => 'suite:wrapper' +task 'suite:pb' => 'suite:server' desc 'Compiles the gRPC extension then runs all the tests' -task all: ['suite:idiomatic', 'suite:bidi', 'suite:server'] +task all: ['suite:idiomatic', 'suite:bidi', 'suite:pb', 'suite:server'] task default: :all diff --git a/src/ruby/bin/grpc_ruby_interop_client b/src/ruby/bin/grpc_ruby_interop_client new file mode 100755 index 0000000000..e79fd33aa5 --- /dev/null +++ b/src/ruby/bin/grpc_ruby_interop_client @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby + +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Provides a gem binary entry point for the interop client. +require 'test/client' diff --git a/src/ruby/bin/grpc_ruby_interop_server b/src/ruby/bin/grpc_ruby_interop_server new file mode 100755 index 0000000000..656a5f7c99 --- /dev/null +++ b/src/ruby/bin/grpc_ruby_interop_server @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby + +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Provides a gem binary entry point for the interop server +require 'test/server' diff --git a/src/ruby/bin/interop/README.md b/src/ruby/bin/interop/README.md deleted file mode 100644 index 84fc663620..0000000000 --- a/src/ruby/bin/interop/README.md +++ /dev/null @@ -1,8 +0,0 @@ -Interop test protos -=================== - -These ruby classes were generated with protoc v3, using grpc's ruby compiler -plugin. - -- As of 2015/01 protoc v3 is available in the -[google-protobuf](https://github.com/google/protobuf) repo diff --git a/src/ruby/bin/interop/interop_client.rb b/src/ruby/bin/interop/interop_client.rb index 78ae217fa5..239083f37f 100755 --- a/src/ruby/bin/interop/interop_client.rb +++ b/src/ruby/bin/interop/interop_client.rb @@ -29,6 +29,12 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ####################################################################### +# DEPRECATED: The behaviour in this file has been moved to pb/test/client.rb +# +# This file remains to support existing tools and scripts that use it. +# ###################################################################### +# # interop_client is a testing tool that accesses a gRPC interop testing # server and runs a test on it. # @@ -39,397 +45,7 @@ # --test_case=<testcase_name> this_dir = File.expand_path(File.dirname(__FILE__)) -lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib') -$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) -$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir) - -require 'optparse' -require 'minitest' -require 'minitest/assertions' - -require 'grpc' -require 'googleauth' -require 'google/protobuf' - -require 'test/cpp/interop/test_services' -require 'test/cpp/interop/messages' -require 'test/cpp/interop/empty' - -require 'signet/ssl_config' - -AUTH_ENV = Google::Auth::CredentialsLoader::ENV_VAR - -# loads the certificates used to access the test server securely. -def load_test_certs - this_dir = File.expand_path(File.dirname(__FILE__)) - data_dir = File.join(File.dirname(File.dirname(this_dir)), 'spec/testdata') - files = ['ca.pem', 'server1.key', 'server1.pem'] - 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? - GRPC.logger.info("loading prod certs from #{ENV['SSL_CERT_FILE']}") - File.open(ENV['SSL_CERT_FILE']).read -end - -# creates SSL Credentials from the test certificates. -def test_creds - certs = load_test_certs - GRPC::Core::Credentials.new(certs[0]) -end - -# creates SSL Credentials from the production certificates. -def prod_creds - cert_text = load_prod_cert - GRPC::Core::Credentials.new(cert_text) -end - -# creates the SSL Credentials. -def ssl_creds(use_test_ca) - return test_creds if use_test_ca - prod_creds -end - -# creates a test stub that accesses host:port securely. -def create_stub(opts) - address = "#{opts.host}:#{opts.port}" - if opts.secure - stub_opts = { - :creds => ssl_creds(opts.use_test_ca), - GRPC::Core::Channel::SSL_TARGET => opts.host_override - } - - # Add service account creds if specified - wants_creds = %w(all compute_engine_creds service_account_creds) - if wants_creds.include?(opts.test_case) - unless opts.oauth_scope.nil? - auth_creds = Google::Auth.get_application_default(opts.oauth_scope) - stub_opts[:update_metadata] = auth_creds.updater_proc - end - end - - if opts.test_case == 'oauth2_auth_token' - auth_creds = Google::Auth.get_application_default(opts.oauth_scope) - kw = auth_creds.updater_proc.call({}) # gives as an auth token - - # use a metadata update proc that just adds the auth token. - stub_opts[:update_metadata] = proc { |md| md.merge(kw) } - end - - if opts.test_case == 'jwt_token_creds' # don't use a scope - auth_creds = Google::Auth.get_application_default - stub_opts[:update_metadata] = auth_creds.updater_proc - end - - GRPC.logger.info("... connecting securely to #{address}") - Grpc::Testing::TestService::Stub.new(address, **stub_opts) - else - GRPC.logger.info("... connecting insecurely to #{address}") - Grpc::Testing::TestService::Stub.new(address) - end -end - -# produces a string of null chars (\0) of length l. -def nulls(l) - fail 'requires #{l} to be +ve' if l < 0 - [].pack('x' * l).force_encoding('utf-8') -end - -# a PingPongPlayer implements the ping pong bidi test. -class PingPongPlayer - include Minitest::Assertions - include Grpc::Testing - include Grpc::Testing::PayloadType - attr_accessor :assertions # required by Minitest::Assertions - attr_accessor :queue - attr_accessor :canceller_op - - # reqs is the enumerator over the requests - def initialize(msg_sizes) - @queue = Queue.new - @msg_sizes = msg_sizes - @assertions = 0 # required by Minitest::Assertions - @canceller_op = nil # used to cancel after the first response - end - - def each_item - return enum_for(:each_item) unless block_given? - req_cls, p_cls = StreamingOutputCallRequest, ResponseParameters # short - count = 0 - @msg_sizes.each do |m| - req_size, resp_size = m - req = req_cls.new(payload: Payload.new(body: nulls(req_size)), - response_type: :COMPRESSABLE, - response_parameters: [p_cls.new(size: resp_size)]) - yield req - resp = @queue.pop - assert_equal(:COMPRESSABLE, resp.payload.type, 'payload type is wrong') - assert_equal(resp_size, resp.payload.body.length, - "payload body #{count} has the wrong length") - p "OK: ping_pong #{count}" - count += 1 - unless @canceller_op.nil? - canceller_op.cancel - break - end - end - end -end - -# defines methods corresponding to each interop test case. -class NamedTests - include Minitest::Assertions - include Grpc::Testing - include Grpc::Testing::PayloadType - attr_accessor :assertions # required by Minitest::Assertions - - def initialize(stub, args) - @assertions = 0 # required by Minitest::Assertions - @stub = stub - @args = args - end - - def empty_unary - resp = @stub.empty_call(Empty.new) - assert resp.is_a?(Empty), 'empty_unary: invalid response' - p 'OK: empty_unary' - end - - def large_unary - perform_large_unary - p 'OK: large_unary' - end - - def service_account_creds - # ignore this test if the oauth options are not set - if @args.oauth_scope.nil? - p 'NOT RUN: service_account_creds; no service_account settings' - return - end - json_key = File.read(ENV[AUTH_ENV]) - wanted_email = MultiJson.load(json_key)['client_email'] - resp = perform_large_unary(fill_username: true, - fill_oauth_scope: true) - assert_equal(wanted_email, resp.username, - 'service_account_creds: incorrect username') - assert(@args.oauth_scope.include?(resp.oauth_scope), - 'service_account_creds: incorrect oauth_scope') - p 'OK: service_account_creds' - end - - def jwt_token_creds - json_key = File.read(ENV[AUTH_ENV]) - wanted_email = MultiJson.load(json_key)['client_email'] - resp = perform_large_unary(fill_username: true) - assert_equal(wanted_email, resp.username, - 'service_account_creds: incorrect username') - p 'OK: jwt_token_creds' - end - - def compute_engine_creds - resp = perform_large_unary(fill_username: true, - fill_oauth_scope: true) - assert_equal(@args.default_service_account, resp.username, - 'compute_engine_creds: incorrect username') - p 'OK: compute_engine_creds' - end - - def oauth2_auth_token - resp = perform_large_unary(fill_username: true, - fill_oauth_scope: true) - json_key = File.read(ENV[AUTH_ENV]) - wanted_email = MultiJson.load(json_key)['client_email'] - assert_equal(wanted_email, resp.username, - "#{__callee__}: incorrect username") - assert(@args.oauth_scope.include?(resp.oauth_scope), - "#{__callee__}: incorrect oauth_scope") - p "OK: #{__callee__}" - end - - def per_rpc_creds - auth_creds = Google::Auth.get_application_default(@args.oauth_scope) - kw = auth_creds.updater_proc.call({}) - resp = perform_large_unary(fill_username: true, - fill_oauth_scope: true, - **kw) - json_key = File.read(ENV[AUTH_ENV]) - wanted_email = MultiJson.load(json_key)['client_email'] - assert_equal(wanted_email, resp.username, - "#{__callee__}: incorrect username") - assert(@args.oauth_scope.include?(resp.oauth_scope), - "#{__callee__}: incorrect oauth_scope") - p "OK: #{__callee__}" - end - - def client_streaming - msg_sizes = [27_182, 8, 1828, 45_904] - wanted_aggregate_size = 74_922 - reqs = msg_sizes.map do |x| - req = Payload.new(body: nulls(x)) - StreamingInputCallRequest.new(payload: req) - end - resp = @stub.streaming_input_call(reqs) - assert_equal(wanted_aggregate_size, resp.aggregated_payload_size, - 'client_streaming: aggregate payload size is incorrect') - p 'OK: client_streaming' - end - - def server_streaming - msg_sizes = [31_415, 9, 2653, 58_979] - response_spec = msg_sizes.map { |s| ResponseParameters.new(size: s) } - req = StreamingOutputCallRequest.new(response_type: :COMPRESSABLE, - response_parameters: response_spec) - resps = @stub.streaming_output_call(req) - resps.each_with_index do |r, i| - assert i < msg_sizes.length, 'too many responses' - assert_equal(:COMPRESSABLE, r.payload.type, - 'payload type is wrong') - assert_equal(msg_sizes[i], r.payload.body.length, - 'payload body #{i} has the wrong length') - end - p 'OK: server_streaming' - end - - def ping_pong - msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]] - ppp = PingPongPlayer.new(msg_sizes) - resps = @stub.full_duplex_call(ppp.each_item) - resps.each { |r| ppp.queue.push(r) } - p 'OK: ping_pong' - end - - def timeout_on_sleeping_server - msg_sizes = [[27_182, 31_415]] - ppp = PingPongPlayer.new(msg_sizes) - resps = @stub.full_duplex_call(ppp.each_item, timeout: 0.001) - resps.each { |r| ppp.queue.push(r) } - fail 'Should have raised GRPC::BadStatus(DEADLINE_EXCEEDED)' - rescue GRPC::BadStatus => e - assert_equal(e.code, GRPC::Core::StatusCodes::DEADLINE_EXCEEDED) - p "OK: #{__callee__}" - end - - def empty_stream - ppp = PingPongPlayer.new([]) - resps = @stub.full_duplex_call(ppp.each_item) - count = 0 - resps.each do - |r| ppp.queue.push(r) - count += 1 - end - assert_equal(0, count, 'too many responses, expect 0') - p 'OK: empty_stream' - end - - def cancel_after_begin - msg_sizes = [27_182, 8, 1828, 45_904] - reqs = msg_sizes.map do |x| - req = Payload.new(body: nulls(x)) - StreamingInputCallRequest.new(payload: req) - end - op = @stub.streaming_input_call(reqs, return_op: true) - op.cancel - assert_raises(GRPC::Cancelled) { op.execute } - assert(op.cancelled, 'call operation should be CANCELLED') - p 'OK: cancel_after_begin' - end - - def cancel_after_first_response - msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]] - ppp = PingPongPlayer.new(msg_sizes) - op = @stub.full_duplex_call(ppp.each_item, return_op: true) - ppp.canceller_op = op # causes ppp to cancel after the 1st message - assert_raises(GRPC::Cancelled) { op.execute.each { |r| ppp.queue.push(r) } } - op.wait - assert(op.cancelled, 'call operation was not CANCELLED') - p 'OK: cancel_after_first_response' - end - - def all - all_methods = NamedTests.instance_methods(false).map(&:to_s) - all_methods.each do |m| - next if m == 'all' || m.start_with?('assert') - p "TESTCASE: #{m}" - method(m).call - end - end - - private - - def perform_large_unary(fill_username: false, fill_oauth_scope: false, **kw) - req_size, wanted_response_size = 271_828, 314_159 - payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size)) - req = SimpleRequest.new(response_type: :COMPRESSABLE, - response_size: wanted_response_size, - payload: payload) - req.fill_username = fill_username - req.fill_oauth_scope = fill_oauth_scope - resp = @stub.unary_call(req, **kw) - assert_equal(:COMPRESSABLE, resp.payload.type, - 'large_unary: payload had the wrong type') - assert_equal(wanted_response_size, resp.payload.body.length, - 'large_unary: payload had the wrong length') - assert_equal(nulls(wanted_response_size), resp.payload.body, - 'large_unary: payload content is invalid') - resp - end -end - -# Args is used to hold the command line info. -Args = Struct.new(:default_service_account, :host, :host_override, - :oauth_scope, :port, :secure, :test_case, - :use_test_ca) - -# validates the the command line options, returning them as a Hash. -def parse_args - args = Args.new - args.host_override = 'foo.test.google.fr' - OptionParser.new do |opts| - opts.on('--oauth_scope scope', - 'Scope for OAuth tokens') { |v| args['oauth_scope'] = v } - opts.on('--server_host SERVER_HOST', 'server hostname') do |v| - args['host'] = v - end - opts.on('--default_service_account email_address', - 'email address of the default service account') do |v| - args['default_service_account'] = v - end - opts.on('--server_host_override HOST_OVERRIDE', - 'override host via a HTTP header') do |v| - args['host_override'] = v - end - opts.on('--server_port SERVER_PORT', 'server port') { |v| args['port'] = v } - # instance_methods(false) gives only the methods defined in that class - test_cases = NamedTests.instance_methods(false).map(&:to_s) - test_case_list = test_cases.join(',') - opts.on('--test_case CODE', test_cases, {}, 'select a test_case', - " (#{test_case_list})") { |v| args['test_case'] = v } - opts.on('-s', '--use_tls', 'require a secure connection?') do |v| - args['secure'] = v - end - opts.on('-t', '--use_test_ca', - 'if secure, use the test certificate?') do |v| - args['use_test_ca'] = v - end - end.parse! - _check_args(args) -end - -def _check_args(args) - %w(host port test_case).each do |a| - if args[a].nil? - fail(OptionParser::MissingArgument, "please specify --#{arg}") - end - end - args -end - -def main - opts = parse_args - stub = create_stub(opts) - NamedTests.new(stub, opts).method(opts['test_case']).call -end +pb_dir = File.join(File.dirname(File.dirname(this_dir)), 'pb') +$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir) -main +require 'test/client' diff --git a/src/ruby/bin/interop/interop_server.rb b/src/ruby/bin/interop/interop_server.rb index 2ba8d2c19e..c6b0d00ec6 100755 --- a/src/ruby/bin/interop/interop_server.rb +++ b/src/ruby/bin/interop/interop_server.rb @@ -29,6 +29,12 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ####################################################################### +# DEPRECATED: The behaviour in this file has been moved to pb/test/server.rb +# +# This file remains to support existing tools and scripts that use it. +# ###################################################################### +# # interop_server is a Testing app that runs a gRPC interop testing server. # # It helps validate interoperation b/w gRPC in different environments @@ -38,157 +44,7 @@ # Usage: $ path/to/interop_server.rb --port this_dir = File.expand_path(File.dirname(__FILE__)) -lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib') -$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) -$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir) - -require 'forwardable' -require 'optparse' - -require 'grpc' - -require 'test/cpp/interop/test_services' -require 'test/cpp/interop/messages' -require 'test/cpp/interop/empty' - -# loads the certificates by the test server. -def load_test_certs - this_dir = File.expand_path(File.dirname(__FILE__)) - data_dir = File.join(File.dirname(File.dirname(this_dir)), 'spec/testdata') - files = ['ca.pem', 'server1.key', 'server1.pem'] - files.map { |f| File.open(File.join(data_dir, f)).read } -end - -# creates a ServerCredentials from the test certificates. -def test_server_creds - certs = load_test_certs - GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2]) -end - -# produces a string of null chars (\0) of length l. -def nulls(l) - fail 'requires #{l} to be +ve' if l < 0 - [].pack('x' * l).force_encoding('utf-8') -end - -# A EnumeratorQueue wraps a Queue yielding the items added to it via each_item. -class EnumeratorQueue - extend Forwardable - def_delegators :@q, :push - - def initialize(sentinel) - @q = Queue.new - @sentinel = sentinel - end - - def each_item - return enum_for(:each_item) unless block_given? - loop do - r = @q.pop - break if r.equal?(@sentinel) - fail r if r.is_a? Exception - yield r - end - end -end - -# A runnable implementation of the schema-specified testing service, with each -# service method implemented as required by the interop testing spec. -class TestTarget < Grpc::Testing::TestService::Service - include Grpc::Testing - include Grpc::Testing::PayloadType - - def empty_call(_empty, _call) - Empty.new - end - - def unary_call(simple_req, _call) - req_size = simple_req.response_size - SimpleResponse.new(payload: Payload.new(type: :COMPRESSABLE, - body: nulls(req_size))) - end - - def streaming_input_call(call) - sizes = call.each_remote_read.map { |x| x.payload.body.length } - sum = sizes.inject { |s, x| s + x } - StreamingInputCallResponse.new(aggregated_payload_size: sum) - end - - def streaming_output_call(req, _call) - cls = StreamingOutputCallResponse - req.response_parameters.map do |p| - cls.new(payload: Payload.new(type: req.response_type, - body: nulls(p.size))) - end - end - - def full_duplex_call(reqs) - # reqs is a lazy Enumerator of the requests sent by the client. - q = EnumeratorQueue.new(self) - cls = StreamingOutputCallResponse - Thread.new do - begin - GRPC.logger.info('interop-server: started receiving') - reqs.each do |req| - resp_size = req.response_parameters[0].size - GRPC.logger.info("read a req, response size is #{resp_size}") - resp = cls.new(payload: Payload.new(type: req.response_type, - body: nulls(resp_size))) - q.push(resp) - end - GRPC.logger.info('interop-server: finished receiving') - q.push(self) - rescue StandardError => e - GRPC.logger.info('interop-server: failed') - GRPC.logger.warn(e) - q.push(e) # share the exception with the enumerator - end - end - q.each_item - end - - def half_duplex_call(reqs) - # TODO: update with unique behaviour of the half_duplex_call if that's - # ever required by any of the tests. - full_duplex_call(reqs) - end -end - -# validates the the command line options, returning them as a Hash. -def parse_options - options = { - '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('-s', '--use_tls', 'require a secure connection?') do |v| - options['secure'] = v - end - end.parse! - - if options['port'].nil? - fail(OptionParser::MissingArgument, 'please specify --port') - end - options -end - -def main - opts = parse_options - host = "0.0.0.0:#{opts['port']}" - s = GRPC::RpcServer.new - if opts['secure'] - s.add_http2_port(host, test_server_creds) - GRPC.logger.info("... running securely on #{host}") - else - s.add_http2_port(host) - GRPC.logger.info("... running insecurely on #{host}") - end - s.handle(TestTarget) - s.run_till_terminated -end +pb_dir = File.join(File.dirname(File.dirname(this_dir)), 'pb') +$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir) -main +require 'test/server' diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c index b09d4e2cd9..6b5beb6f5d 100644 --- a/src/ruby/ext/grpc/rb_call.c +++ b/src/ruby/ext/grpc/rb_call.c @@ -82,6 +82,10 @@ static ID id_metadata; * received by the call and subsequently saved on it. */ static ID id_status; +/* id_write_flag is name of the attribute used to access the write_flag + * saved on the call. */ +static ID id_write_flag; + /* sym_* are the symbol for attributes of grpc_rb_sBatchResult. */ static VALUE sym_send_message; static VALUE sym_send_metadata; @@ -240,6 +244,30 @@ static VALUE grpc_rb_call_set_metadata(VALUE self, VALUE metadata) { return rb_ivar_set(self, id_metadata, metadata); } +/* + call-seq: + write_flag = call.write_flag + + Gets the write_flag value saved the call. */ +static VALUE grpc_rb_call_get_write_flag(VALUE self) { + return rb_ivar_get(self, id_write_flag); +} + +/* + call-seq: + call.write_flag = write_flag + + Saves the write_flag on the call. */ +static VALUE grpc_rb_call_set_write_flag(VALUE self, VALUE write_flag) { + if (!NIL_P(write_flag) && TYPE(write_flag) != T_FIXNUM) { + rb_raise(rb_eTypeError, "bad write_flag: got:<%s> want: <Fixnum>", + rb_obj_classname(write_flag)); + return Qnil; + } + + return rb_ivar_set(self, id_write_flag, write_flag); +} + /* grpc_rb_md_ary_fill_hash_cb is the hash iteration callback used to fill grpc_metadata_array. @@ -437,17 +465,19 @@ typedef struct run_batch_stack { grpc_status_code recv_status; char *recv_status_details; size_t recv_status_details_capacity; + uint write_flag; } run_batch_stack; /* grpc_run_batch_stack_init ensures the run_batch_stack is properly * initialized */ -static void grpc_run_batch_stack_init(run_batch_stack *st) { +static void grpc_run_batch_stack_init(run_batch_stack *st, uint write_flag) { MEMZERO(st, run_batch_stack, 1); grpc_metadata_array_init(&st->send_metadata); grpc_metadata_array_init(&st->send_trailing_metadata); grpc_metadata_array_init(&st->recv_metadata); grpc_metadata_array_init(&st->recv_trailing_metadata); st->op_num = 0; + st->write_flag = write_flag; } /* grpc_run_batch_stack_cleanup ensures the run_batch_stack is properly @@ -477,6 +507,7 @@ static void grpc_run_batch_stack_fill_ops(run_batch_stack *st, VALUE ops_hash) { for (i = 0; i < (size_t)RARRAY_LEN(ops_ary); i++) { this_op = rb_ary_entry(ops_ary, i); this_value = rb_hash_aref(ops_hash, this_op); + st->ops[st->op_num].flags = 0; switch (NUM2INT(this_op)) { case GRPC_OP_SEND_INITIAL_METADATA: /* N.B. later there is no need to explicitly delete the metadata keys @@ -490,6 +521,7 @@ static void grpc_run_batch_stack_fill_ops(run_batch_stack *st, VALUE ops_hash) { case GRPC_OP_SEND_MESSAGE: st->ops[st->op_num].data.send_message = grpc_rb_s_to_byte_buffer( RSTRING_PTR(this_value), RSTRING_LEN(this_value)); + st->ops[st->op_num].flags = st->write_flag; break; case GRPC_OP_SEND_CLOSE_FROM_CLIENT: break; @@ -525,7 +557,7 @@ static void grpc_run_batch_stack_fill_ops(run_batch_stack *st, VALUE ops_hash) { NUM2INT(this_op)); }; st->ops[st->op_num].op = (grpc_op_type)NUM2INT(this_op); - st->ops[st->op_num].flags = 0; + st->ops[st->op_num].reserved = NULL; st->op_num++; } } @@ -603,6 +635,8 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE cqueue, VALUE tag, grpc_event ev; grpc_call_error err; VALUE result = Qnil; + VALUE rb_write_flag = rb_ivar_get(self, id_write_flag); + uint write_flag = 0; TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call); /* Validate the ops args, adding them to a ruby array */ @@ -610,7 +644,10 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE cqueue, VALUE tag, rb_raise(rb_eTypeError, "call#run_batch: ops hash should be a hash"); return Qnil; } - grpc_run_batch_stack_init(&st); + if (rb_write_flag != Qnil) { + write_flag = NUM2UINT(rb_write_flag); + } + grpc_run_batch_stack_init(&st, write_flag); grpc_run_batch_stack_fill_ops(&st, ops_hash); /* call grpc_call_start_batch, then wait for it to complete using @@ -637,6 +674,16 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE cqueue, VALUE tag, return result; } +static void Init_grpc_write_flags() { + /* Constants representing the write flags in grpc.h */ + VALUE grpc_rb_mWriteFlags = + rb_define_module_under(grpc_rb_mGrpcCore, "WriteFlags"); + rb_define_const(grpc_rb_mWriteFlags, "BUFFER_HINT", + UINT2NUM(GRPC_WRITE_BUFFER_HINT)); + rb_define_const(grpc_rb_mWriteFlags, "NO_COMPRESS", + UINT2NUM(GRPC_WRITE_NO_COMPRESS)); +} + static void Init_grpc_error_codes() { /* Constants representing the error codes of grpc_call_error in grpc.h */ VALUE grpc_rb_mRpcErrors = @@ -734,10 +781,14 @@ void Init_grpc_call() { rb_define_method(grpc_rb_cCall, "status=", grpc_rb_call_set_status, 1); rb_define_method(grpc_rb_cCall, "metadata", grpc_rb_call_get_metadata, 0); rb_define_method(grpc_rb_cCall, "metadata=", grpc_rb_call_set_metadata, 1); + rb_define_method(grpc_rb_cCall, "write_flag", grpc_rb_call_get_write_flag, 0); + rb_define_method(grpc_rb_cCall, "write_flag=", grpc_rb_call_set_write_flag, + 1); /* Ids used to support call attributes */ id_metadata = rb_intern("metadata"); id_status = rb_intern("status"); + id_write_flag = rb_intern("write_flag"); /* Ids used by the c wrapping internals. */ id_cq = rb_intern("__cq"); @@ -765,6 +816,7 @@ void Init_grpc_call() { Init_grpc_error_codes(); Init_grpc_op_codes(); + Init_grpc_write_flags(); } /* Gets the call from the ruby object */ diff --git a/src/ruby/grpc.gemspec b/src/ruby/grpc.gemspec index eb748458b9..20a6206e7e 100755 --- a/src/ruby/grpc.gemspec +++ b/src/ruby/grpc.gemspec @@ -24,16 +24,16 @@ Gem::Specification.new do |s| %w(math noproto).each do |b| s.executables += ["#{b}_client.rb", "#{b}_server.rb"] end - s.require_paths = %w( bin lib ) + s.executables += %w(grpc_ruby_interop_client grpc_ruby_interop_server) + s.require_paths = %w( bin lib pb ) s.platform = Gem::Platform::RUBY s.add_dependency 'google-protobuf', '~> 3.0.0alpha.1.1' - s.add_dependency 'googleauth', '~> 0.4' # reqd for interop tests - s.add_dependency 'logging', '~> 2.0' - s.add_dependency 'minitest', '~> 5.4' # reqd for interop tests + s.add_dependency 'googleauth', '~> 0.4' - s.add_development_dependency 'simplecov', '~> 0.9' s.add_development_dependency 'bundler', '~> 1.9' + s.add_development_dependency 'logging', '~> 2.0' + s.add_development_dependency 'simplecov', '~> 0.9' s.add_development_dependency 'rake', '~> 10.4' s.add_development_dependency 'rake-compiler', '~> 0.9' s.add_development_dependency 'rspec', '~> 3.2' diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb index 17da401c6b..d9cb924735 100644 --- a/src/ruby/lib/grpc/generic/active_call.rb +++ b/src/ruby/lib/grpc/generic/active_call.rb @@ -59,7 +59,7 @@ module GRPC include Core::CallOps extend Forwardable attr_reader(:deadline) - def_delegators :@call, :cancel, :metadata + def_delegators :@call, :cancel, :metadata, :write_flag, :write_flag= # client_invoke begins a client invocation. # @@ -484,6 +484,7 @@ module GRPC # Operation limits access to an ActiveCall's methods for use as # a Operation on the client. Operation = view_class(:cancel, :cancelled, :deadline, :execute, - :metadata, :status, :start_call, :wait) + :metadata, :status, :start_call, :wait, :write_flag, + :write_flag=) end end diff --git a/src/ruby/lib/grpc/logconfig.rb b/src/ruby/lib/grpc/logconfig.rb index e9b4aa3c95..6b442febcb 100644 --- a/src/ruby/lib/grpc/logconfig.rb +++ b/src/ruby/lib/grpc/logconfig.rb @@ -27,17 +27,33 @@ # (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 'logging' - # GRPC contains the General RPC module. module GRPC - extend Logging.globally -end + # DefaultLogger is a module included in GRPC if no other logging is set up for + # it. See ../spec/spec_helpers an example of where other logging is added. + module DefaultLogger + def logger + LOGGER + end + + private + + # NoopLogger implements the methods of Ruby's conventional logging interface + # that are actually used internally within gRPC with a noop implementation. + class NoopLogger + def info(_ignored) + end -Logging.logger.root.appenders = Logging.appenders.stdout -Logging.logger.root.level = :info + def debug(_ignored) + end -# TODO: provide command-line configuration for logging -Logging.logger['GRPC'].level = :info -Logging.logger['GRPC::ActiveCall'].level = :info -Logging.logger['GRPC::BidiCall'].level = :info + def warn(_ignored) + end + end + + LOGGER = NoopLogger.new + end + + # Inject the noop #logger if no module-level logger method has been injected. + extend DefaultLogger unless methods.include?(:logger) +end diff --git a/src/ruby/pb/README.md b/src/ruby/pb/README.md new file mode 100644 index 0000000000..84644e1098 --- /dev/null +++ b/src/ruby/pb/README.md @@ -0,0 +1,42 @@ +Protocol Buffers +================ + +This folder contains protocol buffers provided with gRPC ruby, and the generated +code to them. + +PREREQUISITES +------------- + +The code is is generated using the protoc (> 3.0.0.alpha.1) and the +grpc_ruby_plugin. These must be installed to regenerate the IDL defined +classes, but that's not necessary just to use them. + +health_check/v1alpha +-------------------- + +This package defines the surface of a simple health check service that gRPC +servers may choose to implement, and provides an implementation for it. To +re-generate the surface. + +```bash +$ # (from this directory) +$ protoc -I . grpc/health/v1alpha/health.proto \ + --grpc_out=. \ + --ruby_out=. \ + --plugin=protoc-gen-grpc=`which grpc_ruby_plugin` +``` + +test +---- + +This package defines the surface of the gRPC interop test service and client +To re-generate the surface, it's necessary to have checked-out versions of +the grpc interop test proto, e.g, by having the full gRPC repository. E.g, + +```bash +$ # (from this directory within the grpc repo) +$ protoc -I../../.. ../../../test/proto/{messages,test,empty}.proto \ + --grpc_out=. \ + --ruby_out=. \ + --plugin=protoc-gen-grpc=`which grpc_ruby_plugin` +``` diff --git a/src/ruby/pb/grpc/health/checker.rb b/src/ruby/pb/grpc/health/checker.rb new file mode 100644 index 0000000000..8c692e74f9 --- /dev/null +++ b/src/ruby/pb/grpc/health/checker.rb @@ -0,0 +1,75 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +require 'grpc' +require 'grpc/health/v1alpha/health_services' +require 'thread' + +module Grpc + # Health contains classes and modules that support providing a health check + # service. + module Health + # Checker is implementation of the schema-specified health checking service. + class Checker < V1alpha::Health::Service + StatusCodes = GRPC::Core::StatusCodes + HealthCheckResponse = V1alpha::HealthCheckResponse + + # Initializes the statuses of participating services + def initialize + @statuses = {} + @status_mutex = Mutex.new # guards access to @statuses + end + + # Implements the rpc IDL API method + def check(req, _call) + status = nil + @status_mutex.synchronize do + status = @statuses["#{req.host}/#{req.service}"] + end + fail GRPC::BadStatus, StatusCodes::NOT_FOUND if status.nil? + HealthCheckResponse.new(status: status) + end + + # Adds the health status for a given host and service. + def add_status(host, service, status) + @status_mutex.synchronize { @statuses["#{host}/#{service}"] = status } + end + + # Clears the status for the given host or service. + def clear_status(host, service) + @status_mutex.synchronize { @statuses.delete("#{host}/#{service}") } + end + + # Clears alls the statuses. + def clear_all + @status_mutex.synchronize { @statuses = {} } + end + end + end +end diff --git a/src/ruby/pb/grpc/health/v1alpha/health.proto b/src/ruby/pb/grpc/health/v1alpha/health.proto new file mode 100644 index 0000000000..d31df1e0a7 --- /dev/null +++ b/src/ruby/pb/grpc/health/v1alpha/health.proto @@ -0,0 +1,50 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package grpc.health.v1alpha; + +message HealthCheckRequest { + string host = 1; + string service = 2; +} + +message HealthCheckResponse { + enum ServingStatus { + UNKNOWN = 0; + SERVING = 1; + NOT_SERVING = 2; + } + ServingStatus status = 1; +} + +service Health { + rpc Check(HealthCheckRequest) returns (HealthCheckResponse); +}
\ No newline at end of file diff --git a/src/ruby/pb/grpc/health/v1alpha/health.rb b/src/ruby/pb/grpc/health/v1alpha/health.rb new file mode 100644 index 0000000000..9c04298ea5 --- /dev/null +++ b/src/ruby/pb/grpc/health/v1alpha/health.rb @@ -0,0 +1,29 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: grpc/health/v1alpha/health.proto + +require 'google/protobuf' + +Google::Protobuf::DescriptorPool.generated_pool.build do + add_message "grpc.health.v1alpha.HealthCheckRequest" do + optional :host, :string, 1 + optional :service, :string, 2 + end + add_message "grpc.health.v1alpha.HealthCheckResponse" do + optional :status, :enum, 1, "grpc.health.v1alpha.HealthCheckResponse.ServingStatus" + end + add_enum "grpc.health.v1alpha.HealthCheckResponse.ServingStatus" do + value :UNKNOWN, 0 + value :SERVING, 1 + value :NOT_SERVING, 2 + end +end + +module Grpc + module Health + module V1alpha + HealthCheckRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1alpha.HealthCheckRequest").msgclass + HealthCheckResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1alpha.HealthCheckResponse").msgclass + HealthCheckResponse::ServingStatus = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1alpha.HealthCheckResponse.ServingStatus").enummodule + end + end +end diff --git a/src/ruby/pb/grpc/health/v1alpha/health_services.rb b/src/ruby/pb/grpc/health/v1alpha/health_services.rb new file mode 100644 index 0000000000..d5cba2e9ec --- /dev/null +++ b/src/ruby/pb/grpc/health/v1alpha/health_services.rb @@ -0,0 +1,28 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# Source: grpc/health/v1alpha/health.proto for package 'grpc.health.v1alpha' + +require 'grpc' +require 'grpc/health/v1alpha/health' + +module Grpc + module Health + module V1alpha + module Health + + # TODO: add proto service documentation here + class Service + + include GRPC::GenericService + + self.marshal_class_method = :encode + self.unmarshal_class_method = :decode + self.service_name = 'grpc.health.v1alpha.Health' + + rpc :Check, HealthCheckRequest, HealthCheckResponse + end + + Stub = Service.rpc_stub_class + end + end + end +end diff --git a/src/ruby/pb/test/client.rb b/src/ruby/pb/test/client.rb new file mode 100755 index 0000000000..164e304b4d --- /dev/null +++ b/src/ruby/pb/test/client.rb @@ -0,0 +1,453 @@ +#!/usr/bin/env ruby + +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# client is a testing tool that accesses a gRPC interop testing server and runs +# a test on it. +# +# Helps validate interoperation b/w different gRPC implementations. +# +# Usage: $ path/to/client.rb --server_host=<hostname> \ +# --server_port=<port> \ +# --test_case=<testcase_name> + +this_dir = File.expand_path(File.dirname(__FILE__)) +lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib') +pb_dir = File.dirname(File.dirname(this_dir)) +$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) +$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir) +$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir) + +require 'optparse' + +require 'grpc' +require 'googleauth' +require 'google/protobuf' + +require 'test/proto/empty' +require 'test/proto/messages' +require 'test/proto/test_services' + +require 'signet/ssl_config' + +AUTH_ENV = Google::Auth::CredentialsLoader::ENV_VAR + +# AssertionError is use to indicate interop test failures. +class AssertionError < RuntimeError; end + +# Fails with AssertionError if the block does evaluate to true +def assert(msg = 'unknown cause') + fail 'No assertion block provided' unless block_given? + fail AssertionError, msg unless yield +end + +# loads the certificates used to access the test server securely. +def load_test_certs + this_dir = File.expand_path(File.dirname(__FILE__)) + data_dir = File.join(File.dirname(File.dirname(this_dir)), 'spec/testdata') + files = ['ca.pem', 'server1.key', 'server1.pem'] + 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? + GRPC.logger.info("loading prod certs from #{ENV['SSL_CERT_FILE']}") + File.open(ENV['SSL_CERT_FILE']).read +end + +# creates SSL Credentials from the test certificates. +def test_creds + certs = load_test_certs + GRPC::Core::Credentials.new(certs[0]) +end + +# creates SSL Credentials from the production certificates. +def prod_creds + cert_text = load_prod_cert + GRPC::Core::Credentials.new(cert_text) +end + +# creates the SSL Credentials. +def ssl_creds(use_test_ca) + return test_creds if use_test_ca + prod_creds +end + +# creates a test stub that accesses host:port securely. +def create_stub(opts) + address = "#{opts.host}:#{opts.port}" + if opts.secure + stub_opts = { + :creds => ssl_creds(opts.use_test_ca), + GRPC::Core::Channel::SSL_TARGET => opts.host_override + } + + # Add service account creds if specified + wants_creds = %w(all compute_engine_creds service_account_creds) + if wants_creds.include?(opts.test_case) + unless opts.oauth_scope.nil? + auth_creds = Google::Auth.get_application_default(opts.oauth_scope) + stub_opts[:update_metadata] = auth_creds.updater_proc + end + end + + if opts.test_case == 'oauth2_auth_token' + auth_creds = Google::Auth.get_application_default(opts.oauth_scope) + kw = auth_creds.updater_proc.call({}) # gives as an auth token + + # use a metadata update proc that just adds the auth token. + stub_opts[:update_metadata] = proc { |md| md.merge(kw) } + end + + if opts.test_case == 'jwt_token_creds' # don't use a scope + auth_creds = Google::Auth.get_application_default + stub_opts[:update_metadata] = auth_creds.updater_proc + end + + GRPC.logger.info("... connecting securely to #{address}") + Grpc::Testing::TestService::Stub.new(address, **stub_opts) + else + GRPC.logger.info("... connecting insecurely to #{address}") + Grpc::Testing::TestService::Stub.new(address) + end +end + +# produces a string of null chars (\0) of length l. +def nulls(l) + fail 'requires #{l} to be +ve' if l < 0 + [].pack('x' * l).force_encoding('utf-8') +end + +# a PingPongPlayer implements the ping pong bidi test. +class PingPongPlayer + include Grpc::Testing + include Grpc::Testing::PayloadType + attr_accessor :queue + attr_accessor :canceller_op + + # reqs is the enumerator over the requests + def initialize(msg_sizes) + @queue = Queue.new + @msg_sizes = msg_sizes + @canceller_op = nil # used to cancel after the first response + end + + def each_item + return enum_for(:each_item) unless block_given? + req_cls, p_cls = StreamingOutputCallRequest, ResponseParameters # short + count = 0 + @msg_sizes.each do |m| + req_size, resp_size = m + req = req_cls.new(payload: Payload.new(body: nulls(req_size)), + response_type: :COMPRESSABLE, + response_parameters: [p_cls.new(size: resp_size)]) + yield req + resp = @queue.pop + assert('payload type is wrong') { :COMPRESSABLE == resp.payload.type } + assert("payload body #{count} has the wrong length") do + resp_size == resp.payload.body.length + end + p "OK: ping_pong #{count}" + count += 1 + unless @canceller_op.nil? + canceller_op.cancel + break + end + end + end +end + +# defines methods corresponding to each interop test case. +class NamedTests + include Grpc::Testing + include Grpc::Testing::PayloadType + + def initialize(stub, args) + @stub = stub + @args = args + end + + def empty_unary + resp = @stub.empty_call(Empty.new) + assert('empty_unary: invalid response') { resp.is_a?(Empty) } + p 'OK: empty_unary' + end + + def large_unary + perform_large_unary + p 'OK: large_unary' + end + + def service_account_creds + # ignore this test if the oauth options are not set + if @args.oauth_scope.nil? + p 'NOT RUN: service_account_creds; no service_account settings' + return + end + json_key = File.read(ENV[AUTH_ENV]) + wanted_email = MultiJson.load(json_key)['client_email'] + resp = perform_large_unary(fill_username: true, + fill_oauth_scope: true) + assert("#{__callee__}: bad username") { wanted_email == resp.username } + assert("#{__callee__}: bad oauth scope") do + @args.oauth_scope.include?(resp.oauth_scope) + end + p "OK: #{__callee__}" + end + + def jwt_token_creds + json_key = File.read(ENV[AUTH_ENV]) + wanted_email = MultiJson.load(json_key)['client_email'] + resp = perform_large_unary(fill_username: true) + assert("#{__callee__}: bad username") { wanted_email == resp.username } + p "OK: #{__callee__}" + end + + def compute_engine_creds + resp = perform_large_unary(fill_username: true, + fill_oauth_scope: true) + assert("#{__callee__}: bad username") do + @args.default_service_account == resp.username + end + p "OK: #{__callee__}" + end + + def oauth2_auth_token + resp = perform_large_unary(fill_username: true, + fill_oauth_scope: true) + json_key = File.read(ENV[AUTH_ENV]) + wanted_email = MultiJson.load(json_key)['client_email'] + assert("#{__callee__}: bad username") { wanted_email == resp.username } + assert("#{__callee__}: bad oauth scope") do + @args.oauth_scope.include?(resp.oauth_scope) + end + p "OK: #{__callee__}" + end + + def per_rpc_creds + auth_creds = Google::Auth.get_application_default(@args.oauth_scope) + kw = auth_creds.updater_proc.call({}) + resp = perform_large_unary(fill_username: true, + fill_oauth_scope: true, + **kw) + json_key = File.read(ENV[AUTH_ENV]) + wanted_email = MultiJson.load(json_key)['client_email'] + assert("#{__callee__}: bad username") { wanted_email == resp.username } + assert("#{__callee__}: bad oauth scope") do + @args.oauth_scope.include?(resp.oauth_scope) + end + p "OK: #{__callee__}" + end + + def client_streaming + msg_sizes = [27_182, 8, 1828, 45_904] + wanted_aggregate_size = 74_922 + reqs = msg_sizes.map do |x| + req = Payload.new(body: nulls(x)) + StreamingInputCallRequest.new(payload: req) + end + resp = @stub.streaming_input_call(reqs) + assert("#{__callee__}: aggregate payload size is incorrect") do + wanted_aggregate_size == resp.aggregated_payload_size + end + p "OK: #{__callee__}" + end + + def server_streaming + msg_sizes = [31_415, 9, 2653, 58_979] + response_spec = msg_sizes.map { |s| ResponseParameters.new(size: s) } + req = StreamingOutputCallRequest.new(response_type: :COMPRESSABLE, + response_parameters: response_spec) + resps = @stub.streaming_output_call(req) + resps.each_with_index do |r, i| + assert("#{__callee__}: too many responses") { i < msg_sizes.length } + assert("#{__callee__}: payload body #{i} has the wrong length") do + msg_sizes[i] == r.payload.body.length + end + assert("#{__callee__}: payload type is wrong") do + :COMPRESSABLE == r.payload.type + end + end + p "OK: #{__callee__}" + end + + def ping_pong + msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]] + ppp = PingPongPlayer.new(msg_sizes) + resps = @stub.full_duplex_call(ppp.each_item) + resps.each { |r| ppp.queue.push(r) } + p "OK: #{__callee__}" + end + + def timeout_on_sleeping_server + msg_sizes = [[27_182, 31_415]] + ppp = PingPongPlayer.new(msg_sizes) + resps = @stub.full_duplex_call(ppp.each_item, timeout: 0.001) + resps.each { |r| ppp.queue.push(r) } + fail 'Should have raised GRPC::BadStatus(DEADLINE_EXCEEDED)' + rescue GRPC::BadStatus => e + assert("#{__callee__}: status was wrong") do + e.code == GRPC::Core::StatusCodes::DEADLINE_EXCEEDED + end + p "OK: #{__callee__}" + end + + def empty_stream + ppp = PingPongPlayer.new([]) + resps = @stub.full_duplex_call(ppp.each_item) + count = 0 + resps.each do |r| + ppp.queue.push(r) + count += 1 + end + assert("#{__callee__}: too many responses expected 0") do + count == 0 + end + p "OK: #{__callee__}" + end + + def cancel_after_begin + msg_sizes = [27_182, 8, 1828, 45_904] + reqs = msg_sizes.map do |x| + req = Payload.new(body: nulls(x)) + StreamingInputCallRequest.new(payload: req) + end + op = @stub.streaming_input_call(reqs, return_op: true) + op.cancel + op.execute + fail 'Should have raised GRPC:Cancelled' + rescue GRPC::Cancelled + assert("#{__callee__}: call operation should be CANCELLED") { op.cancelled } + p "OK: #{__callee__}" + end + + def cancel_after_first_response + msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]] + ppp = PingPongPlayer.new(msg_sizes) + op = @stub.full_duplex_call(ppp.each_item, return_op: true) + ppp.canceller_op = op # causes ppp to cancel after the 1st message + op.execute.each { |r| ppp.queue.push(r) } + fail 'Should have raised GRPC:Cancelled' + rescue GRPC::Cancelled + assert("#{__callee__}: call operation should be CANCELLED") { op.cancelled } + op.wait + p "OK: #{__callee__}" + end + + def all + all_methods = NamedTests.instance_methods(false).map(&:to_s) + all_methods.each do |m| + next if m == 'all' || m.start_with?('assert') + p "TESTCASE: #{m}" + method(m).call + end + end + + private + + def perform_large_unary(fill_username: false, fill_oauth_scope: false, **kw) + req_size, wanted_response_size = 271_828, 314_159 + payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size)) + req = SimpleRequest.new(response_type: :COMPRESSABLE, + response_size: wanted_response_size, + payload: payload) + req.fill_username = fill_username + req.fill_oauth_scope = fill_oauth_scope + resp = @stub.unary_call(req, **kw) + assert('payload type is wrong') do + :COMPRESSABLE == resp.payload.type + end + assert('payload body has the wrong length') do + wanted_response_size == resp.payload.body.length + end + assert('payload body is invalid') do + nulls(wanted_response_size) == resp.payload.body + end + resp + end +end + +# Args is used to hold the command line info. +Args = Struct.new(:default_service_account, :host, :host_override, + :oauth_scope, :port, :secure, :test_case, + :use_test_ca) + +# validates the the command line options, returning them as a Hash. +def parse_args + args = Args.new + args.host_override = 'foo.test.google.fr' + OptionParser.new do |opts| + opts.on('--oauth_scope scope', + 'Scope for OAuth tokens') { |v| args['oauth_scope'] = v } + opts.on('--server_host SERVER_HOST', 'server hostname') do |v| + args['host'] = v + end + opts.on('--default_service_account email_address', + 'email address of the default service account') do |v| + args['default_service_account'] = v + end + opts.on('--server_host_override HOST_OVERRIDE', + 'override host via a HTTP header') do |v| + args['host_override'] = v + end + opts.on('--server_port SERVER_PORT', 'server port') { |v| args['port'] = v } + # instance_methods(false) gives only the methods defined in that class + test_cases = NamedTests.instance_methods(false).map(&:to_s) + test_case_list = test_cases.join(',') + opts.on('--test_case CODE', test_cases, {}, 'select a test_case', + " (#{test_case_list})") { |v| args['test_case'] = v } + opts.on('-s', '--use_tls', 'require a secure connection?') do |v| + args['secure'] = v + end + opts.on('-t', '--use_test_ca', + 'if secure, use the test certificate?') do |v| + args['use_test_ca'] = v + end + end.parse! + _check_args(args) +end + +def _check_args(args) + %w(host port test_case).each do |a| + if args[a].nil? + fail(OptionParser::MissingArgument, "please specify --#{a}") + end + end + args +end + +def main + opts = parse_args + stub = create_stub(opts) + NamedTests.new(stub, opts).method(opts['test_case']).call +end + +main diff --git a/src/ruby/pb/test/proto/empty.rb b/src/ruby/pb/test/proto/empty.rb new file mode 100644 index 0000000000..559adcc85e --- /dev/null +++ b/src/ruby/pb/test/proto/empty.rb @@ -0,0 +1,15 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: test/proto/empty.proto + +require 'google/protobuf' + +Google::Protobuf::DescriptorPool.generated_pool.build do + add_message "grpc.testing.Empty" do + end +end + +module Grpc + module Testing + Empty = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Empty").msgclass + end +end diff --git a/src/ruby/bin/interop/test/cpp/interop/messages.rb b/src/ruby/pb/test/proto/messages.rb index 89c349b406..9b7f977285 100644 --- a/src/ruby/bin/interop/test/cpp/interop/messages.rb +++ b/src/ruby/pb/test/proto/messages.rb @@ -1,34 +1,5 @@ -# Copyright 2015, Google Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - # Generated by the protocol buffer compiler. DO NOT EDIT! -# source: test/cpp/interop/messages.proto +# source: test/proto/messages.proto require 'google/protobuf' @@ -37,12 +8,18 @@ Google::Protobuf::DescriptorPool.generated_pool.build do optional :type, :enum, 1, "grpc.testing.PayloadType" optional :body, :string, 2 end + add_message "grpc.testing.EchoStatus" do + optional :code, :int32, 1 + optional :message, :string, 2 + end add_message "grpc.testing.SimpleRequest" do optional :response_type, :enum, 1, "grpc.testing.PayloadType" optional :response_size, :int32, 2 optional :payload, :message, 3, "grpc.testing.Payload" optional :fill_username, :bool, 4 optional :fill_oauth_scope, :bool, 5 + optional :response_compression, :enum, 6, "grpc.testing.CompressionType" + optional :response_status, :message, 7, "grpc.testing.EchoStatus" end add_message "grpc.testing.SimpleResponse" do optional :payload, :message, 1, "grpc.testing.Payload" @@ -63,20 +40,32 @@ Google::Protobuf::DescriptorPool.generated_pool.build do optional :response_type, :enum, 1, "grpc.testing.PayloadType" repeated :response_parameters, :message, 2, "grpc.testing.ResponseParameters" optional :payload, :message, 3, "grpc.testing.Payload" + optional :response_compression, :enum, 6, "grpc.testing.CompressionType" + optional :response_status, :message, 7, "grpc.testing.EchoStatus" end add_message "grpc.testing.StreamingOutputCallResponse" do optional :payload, :message, 1, "grpc.testing.Payload" end + add_message "grpc.testing.ReconnectInfo" do + optional :passed, :bool, 1 + repeated :backoff_ms, :int32, 2 + end add_enum "grpc.testing.PayloadType" do value :COMPRESSABLE, 0 value :UNCOMPRESSABLE, 1 value :RANDOM, 2 end + add_enum "grpc.testing.CompressionType" do + value :NONE, 0 + value :GZIP, 1 + value :DEFLATE, 2 + end end module Grpc module Testing Payload = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.Payload").msgclass + EchoStatus = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.EchoStatus").msgclass SimpleRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.SimpleRequest").msgclass SimpleResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.SimpleResponse").msgclass StreamingInputCallRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingInputCallRequest").msgclass @@ -84,6 +73,8 @@ module Grpc ResponseParameters = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ResponseParameters").msgclass StreamingOutputCallRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingOutputCallRequest").msgclass StreamingOutputCallResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.StreamingOutputCallResponse").msgclass + ReconnectInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.ReconnectInfo").msgclass PayloadType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.PayloadType").enummodule + CompressionType = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.testing.CompressionType").enummodule end end diff --git a/src/ruby/pb/test/proto/test.rb b/src/ruby/pb/test/proto/test.rb new file mode 100644 index 0000000000..100eb6505c --- /dev/null +++ b/src/ruby/pb/test/proto/test.rb @@ -0,0 +1,14 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: test/proto/test.proto + +require 'google/protobuf' + +require 'test/proto/empty' +require 'test/proto/messages' +Google::Protobuf::DescriptorPool.generated_pool.build do +end + +module Grpc + module Testing + end +end diff --git a/src/ruby/pb/test/proto/test_services.rb b/src/ruby/pb/test/proto/test_services.rb new file mode 100644 index 0000000000..9df9cc5860 --- /dev/null +++ b/src/ruby/pb/test/proto/test_services.rb @@ -0,0 +1,64 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# Source: test/proto/test.proto for package 'grpc.testing' + +require 'grpc' +require 'test/proto/test' + +module Grpc + module Testing + module TestService + + # TODO: add proto service documentation here + class Service + + include GRPC::GenericService + + self.marshal_class_method = :encode + self.unmarshal_class_method = :decode + self.service_name = 'grpc.testing.TestService' + + rpc :EmptyCall, Empty, Empty + rpc :UnaryCall, SimpleRequest, SimpleResponse + rpc :StreamingOutputCall, StreamingOutputCallRequest, stream(StreamingOutputCallResponse) + rpc :StreamingInputCall, stream(StreamingInputCallRequest), StreamingInputCallResponse + rpc :FullDuplexCall, stream(StreamingOutputCallRequest), stream(StreamingOutputCallResponse) + rpc :HalfDuplexCall, stream(StreamingOutputCallRequest), stream(StreamingOutputCallResponse) + end + + Stub = Service.rpc_stub_class + end + module UnimplementedService + + # TODO: add proto service documentation here + class Service + + include GRPC::GenericService + + self.marshal_class_method = :encode + self.unmarshal_class_method = :decode + self.service_name = 'grpc.testing.UnimplementedService' + + rpc :UnimplementedCall, Empty, Empty + end + + Stub = Service.rpc_stub_class + end + module ReconnectService + + # TODO: add proto service documentation here + class Service + + include GRPC::GenericService + + self.marshal_class_method = :encode + self.unmarshal_class_method = :decode + self.service_name = 'grpc.testing.ReconnectService' + + rpc :Start, Empty, Empty + rpc :Stop, Empty, ReconnectInfo + end + + Stub = Service.rpc_stub_class + end + end +end diff --git a/src/ruby/pb/test/server.rb b/src/ruby/pb/test/server.rb new file mode 100755 index 0000000000..e2e1ecbd62 --- /dev/null +++ b/src/ruby/pb/test/server.rb @@ -0,0 +1,196 @@ +#!/usr/bin/env ruby + +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# interop_server is a Testing app that runs a gRPC interop testing server. +# +# It helps validate interoperation b/w gRPC in different environments +# +# Helps validate interoperation b/w different gRPC implementations. +# +# Usage: $ path/to/interop_server.rb --port + +this_dir = File.expand_path(File.dirname(__FILE__)) +lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib') +pb_dir = File.dirname(File.dirname(this_dir)) +$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) +$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir) +$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir) + +require 'forwardable' +require 'optparse' + +require 'grpc' + +require 'test/proto/empty' +require 'test/proto/messages' +require 'test/proto/test_services' + +# loads the certificates by the test server. +def load_test_certs + this_dir = File.expand_path(File.dirname(__FILE__)) + data_dir = File.join(File.dirname(File.dirname(this_dir)), 'spec/testdata') + files = ['ca.pem', 'server1.key', 'server1.pem'] + files.map { |f| File.open(File.join(data_dir, f)).read } +end + +# creates a ServerCredentials from the test certificates. +def test_server_creds + certs = load_test_certs + GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2]) +end + +# produces a string of null chars (\0) of length l. +def nulls(l) + fail 'requires #{l} to be +ve' if l < 0 + [].pack('x' * l).force_encoding('utf-8') +end + +# A EnumeratorQueue wraps a Queue yielding the items added to it via each_item. +class EnumeratorQueue + extend Forwardable + def_delegators :@q, :push + + def initialize(sentinel) + @q = Queue.new + @sentinel = sentinel + end + + def each_item + return enum_for(:each_item) unless block_given? + loop do + r = @q.pop + break if r.equal?(@sentinel) + fail r if r.is_a? Exception + yield r + end + end +end + +# A runnable implementation of the schema-specified testing service, with each +# service method implemented as required by the interop testing spec. +class TestTarget < Grpc::Testing::TestService::Service + include Grpc::Testing + include Grpc::Testing::PayloadType + + def empty_call(_empty, _call) + Empty.new + end + + def unary_call(simple_req, _call) + req_size = simple_req.response_size + SimpleResponse.new(payload: Payload.new(type: :COMPRESSABLE, + body: nulls(req_size))) + end + + def streaming_input_call(call) + sizes = call.each_remote_read.map { |x| x.payload.body.length } + sum = sizes.inject { |s, x| s + x } + StreamingInputCallResponse.new(aggregated_payload_size: sum) + end + + def streaming_output_call(req, _call) + cls = StreamingOutputCallResponse + req.response_parameters.map do |p| + cls.new(payload: Payload.new(type: req.response_type, + body: nulls(p.size))) + end + end + + def full_duplex_call(reqs) + # reqs is a lazy Enumerator of the requests sent by the client. + q = EnumeratorQueue.new(self) + cls = StreamingOutputCallResponse + Thread.new do + begin + GRPC.logger.info('interop-server: started receiving') + reqs.each do |req| + resp_size = req.response_parameters[0].size + GRPC.logger.info("read a req, response size is #{resp_size}") + resp = cls.new(payload: Payload.new(type: req.response_type, + body: nulls(resp_size))) + q.push(resp) + end + GRPC.logger.info('interop-server: finished receiving') + q.push(self) + rescue StandardError => e + GRPC.logger.info('interop-server: failed') + GRPC.logger.warn(e) + q.push(e) # share the exception with the enumerator + end + end + q.each_item + end + + def half_duplex_call(reqs) + # TODO: update with unique behaviour of the half_duplex_call if that's + # ever required by any of the tests. + full_duplex_call(reqs) + end +end + +# validates the the command line options, returning them as a Hash. +def parse_options + options = { + '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('-s', '--use_tls', 'require a secure connection?') do |v| + options['secure'] = v + end + end.parse! + + if options['port'].nil? + fail(OptionParser::MissingArgument, 'please specify --port') + end + options +end + +def main + opts = parse_options + host = "0.0.0.0:#{opts['port']}" + s = GRPC::RpcServer.new + if opts['secure'] + s.add_http2_port(host, test_server_creds) + GRPC.logger.info("... running securely on #{host}") + else + s.add_http2_port(host) + GRPC.logger.info("... running insecurely on #{host}") + end + s.handle(TestTarget) + s.run_till_terminated +end + +main diff --git a/src/ruby/spec/call_spec.rb b/src/ruby/spec/call_spec.rb index 3c5d33ffcd..dd3c45f754 100644 --- a/src/ruby/spec/call_spec.rb +++ b/src/ruby/spec/call_spec.rb @@ -31,6 +31,14 @@ require 'grpc' include GRPC::Core::StatusCodes +describe GRPC::Core::WriteFlags do + it 'should define the known write flag values' do + m = GRPC::Core::WriteFlags + expect(m.const_get(:BUFFER_HINT)).to_not be_nil + expect(m.const_get(:NO_COMPRESS)).to_not be_nil + end +end + describe GRPC::Core::RpcErrors do before(:each) do @known_types = { diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb index 26208b714a..fcd7bd082f 100644 --- a/src/ruby/spec/generic/active_call_spec.rb +++ b/src/ruby/spec/generic/active_call_spec.rb @@ -35,6 +35,7 @@ describe GRPC::ActiveCall do ActiveCall = GRPC::ActiveCall Call = GRPC::Core::Call CallOps = GRPC::Core::CallOps + WriteFlags = GRPC::Core::WriteFlags before(:each) do @pass_through = proc { |x| x } @@ -129,6 +130,31 @@ describe GRPC::ActiveCall do @pass_through, deadline) expect(server_call.remote_read).to eq('marshalled:' + msg) end + + TEST_WRITE_FLAGS = [WriteFlags::BUFFER_HINT, WriteFlags::NO_COMPRESS] + TEST_WRITE_FLAGS.each do |f| + it "successfully makes calls with write_flag set to #{f}" do + call = make_test_call + ActiveCall.client_invoke(call, @client_queue) + marshal = proc { |x| 'marshalled:' + x } + client_call = ActiveCall.new(call, @client_queue, marshal, + @pass_through, deadline) + msg = 'message is a string' + client_call.write_flag = f + client_call.remote_send(msg) + + # confirm that the message was marshalled + recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline) + recvd_call = recvd_rpc.call + server_ops = { + CallOps::SEND_INITIAL_METADATA => nil + } + recvd_call.run_batch(@server_queue, @server_tag, deadline, server_ops) + server_call = ActiveCall.new(recvd_call, @server_queue, @pass_through, + @pass_through, deadline) + expect(server_call.remote_read).to eq('marshalled:' + msg) + end + end end describe '#client_invoke' do @@ -261,7 +287,7 @@ describe GRPC::ActiveCall do client_call.writes_done(false) server_call = expect_server_to_receive(msg) e = client_call.each_remote_read - n = 3 # arbitrary value > 1 + n = 3 # arbitrary value > 1 n.times do server_call.remote_send(reply) expect(e.next).to eq(reply) diff --git a/src/ruby/spec/pb/health/checker_spec.rb b/src/ruby/spec/pb/health/checker_spec.rb new file mode 100644 index 0000000000..6999a69105 --- /dev/null +++ b/src/ruby/spec/pb/health/checker_spec.rb @@ -0,0 +1,233 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +require 'grpc' +require 'grpc/health/v1alpha/health' +require 'grpc/health/checker' +require 'open3' + +def can_run_codegen_check + system('which grpc_ruby_plugin') && system('which protoc') +end + +describe 'Health protobuf code generation' do + context 'the health service file used by grpc/health/checker' do + if !can_run_codegen_check + skip 'protoc || grpc_ruby_plugin missing, cannot verify health code-gen' + else + it 'should already be loaded indirectly i.e, used by the other specs' do + expect(require('grpc/health/v1alpha/health_services')).to be(false) + end + + it 'should have the same content as created by code generation' do + root_dir = File.dirname( + File.dirname(File.dirname(File.dirname(__FILE__)))) + pb_dir = File.join(root_dir, 'pb') + + # Get the current content + service_path = File.join(pb_dir, 'grpc', 'health', 'v1alpha', + 'health_services.rb') + want = nil + File.open(service_path) { |f| want = f.read } + + # Regenerate it + plugin, = Open3.capture2('which', 'grpc_ruby_plugin') + plugin = plugin.strip + got = nil + Dir.mktmpdir do |tmp_dir| + gen_out = File.join(tmp_dir, 'grpc', 'health', 'v1alpha', + 'health_services.rb') + pid = spawn( + 'protoc', + '-I.', + 'grpc/health/v1alpha/health.proto', + "--grpc_out=#{tmp_dir}", + "--plugin=protoc-gen-grpc=#{plugin}", + chdir: pb_dir) + Process.wait(pid) + File.open(gen_out) { |f| got = f.read } + end + expect(got).to eq(want) + end + end + end +end + +describe Grpc::Health::Checker do + StatusCodes = GRPC::Core::StatusCodes + ServingStatus = Grpc::Health::V1alpha::HealthCheckResponse::ServingStatus + HCResp = Grpc::Health::V1alpha::HealthCheckResponse + HCReq = Grpc::Health::V1alpha::HealthCheckRequest + success_tests = + [ + { + desc: 'neither host or service are specified', + host: '', + service: '' + }, { + desc: 'only the host is specified', + host: 'test-fake-host', + service: '' + }, { + desc: 'the host and service are specified', + host: 'test-fake-host', + service: 'fake-service-1' + }, { + desc: 'only the service is specified', + host: '', + service: 'fake-service-2' + } + ] + + context 'initialization' do + it 'can be constructed with no args' do + expect(subject).to_not be(nil) + end + end + + context 'method `add_status` and `check`' do + success_tests.each do |t| + it "should succeed when #{t[:desc]}" do + subject.add_status(t[:host], t[:service], ServingStatus::NOT_SERVING) + got = subject.check(HCReq.new(host: t[:host], service: t[:service]), + nil) + want = HCResp.new(status: ServingStatus::NOT_SERVING) + expect(got).to eq(want) + end + end + end + + context 'method `check`' do + success_tests.each do |t| + it "should fail with NOT_FOUND when #{t[:desc]}" do + blk = proc do + subject.check(HCReq.new(host: t[:host], service: t[:service]), nil) + end + expected_msg = /#{StatusCodes::NOT_FOUND}/ + expect(&blk).to raise_error GRPC::BadStatus, expected_msg + end + end + end + + context 'method `clear_status`' do + success_tests.each do |t| + it "should fail after clearing status when #{t[:desc]}" do + subject.add_status(t[:host], t[:service], ServingStatus::NOT_SERVING) + got = subject.check(HCReq.new(host: t[:host], service: t[:service]), + nil) + want = HCResp.new(status: ServingStatus::NOT_SERVING) + expect(got).to eq(want) + + subject.clear_status(t[:host], t[:service]) + blk = proc do + subject.check(HCReq.new(host: t[:host], service: t[:service]), + nil) + end + expected_msg = /#{StatusCodes::NOT_FOUND}/ + expect(&blk).to raise_error GRPC::BadStatus, expected_msg + end + end + end + + context 'method `clear_all`' do + it 'should return NOT_FOUND after being invoked' do + success_tests.each do |t| + subject.add_status(t[:host], t[:service], ServingStatus::NOT_SERVING) + got = subject.check(HCReq.new(host: t[:host], service: t[:service]), + nil) + want = HCResp.new(status: ServingStatus::NOT_SERVING) + expect(got).to eq(want) + end + + subject.clear_all + + success_tests.each do |t| + blk = proc do + subject.check(HCReq.new(host: t[:host], service: t[:service]), nil) + end + expected_msg = /#{StatusCodes::NOT_FOUND}/ + expect(&blk).to raise_error GRPC::BadStatus, expected_msg + end + end + end + + describe 'running on RpcServer' do + RpcServer = GRPC::RpcServer + StatusCodes = GRPC::Core::StatusCodes + CheckerStub = Grpc::Health::Checker.rpc_stub_class + + before(:each) do + @server_queue = GRPC::Core::CompletionQueue.new + server_host = '0.0.0.0:0' + @server = GRPC::Core::Server.new(@server_queue, nil) + server_port = @server.add_http2_port(server_host) + @host = "localhost:#{server_port}" + @ch = GRPC::Core::Channel.new(@host, nil) + @client_opts = { channel_override: @ch } + server_opts = { + server_override: @server, + completion_queue_override: @server_queue, + poll_period: 1 + } + @srv = RpcServer.new(**server_opts) + end + + after(:each) do + @srv.stop + end + + it 'should receive the correct status', server: true do + @srv.handle(subject) + subject.add_status('', '', ServingStatus::NOT_SERVING) + t = Thread.new { @srv.run } + @srv.wait_till_running + + stub = CheckerStub.new(@host, **@client_opts) + got = stub.check(HCReq.new) + want = HCResp.new(status: ServingStatus::NOT_SERVING) + expect(got).to eq(want) + @srv.stop + t.join + end + + it 'should fail on unknown services', server: true do + @srv.handle(subject) + t = Thread.new { @srv.run } + @srv.wait_till_running + blk = proc do + stub = CheckerStub.new(@host, **@client_opts) + stub.check(HCReq.new(host: 'unknown', service: 'unknown')) + end + expected_msg = /#{StatusCodes::NOT_FOUND}/ + expect(&blk).to raise_error GRPC::BadStatus, expected_msg + @srv.stop + t.join + end + end +end diff --git a/src/ruby/spec/spec_helper.rb b/src/ruby/spec/spec_helper.rb index 270d2e97d3..c891c1bf5e 100644 --- a/src/ruby/spec/spec_helper.rb +++ b/src/ruby/spec/spec_helper.rb @@ -47,11 +47,23 @@ require 'rspec' require 'logging' require 'rspec/logging_helper' +# GRPC is the general RPC module +# +# Configure its logging for fine-grained log control during test runs +module GRPC + extend Logging.globally +end +Logging.logger.root.appenders = Logging.appenders.stdout +Logging.logger.root.level = :info +Logging.logger['GRPC'].level = :info +Logging.logger['GRPC::ActiveCall'].level = :info +Logging.logger['GRPC::BidiCall'].level = :info + # Configure RSpec to capture log messages for each test. The output from the # logs will be stored in the @log_output variable. It is a StringIO instance. RSpec.configure do |config| include RSpec::LoggingHelper - config.capture_log_messages + config.capture_log_messages # comment this out to see logs during test runs end RSpec::Expectations.configuration.warn_about_potential_false_positives = false |