diff options
Diffstat (limited to 'src')
37 files changed, 400 insertions, 55 deletions
diff --git a/src/core/ext/README.md b/src/core/ext/README.md new file mode 100644 index 0000000000..0812b20823 --- /dev/null +++ b/src/core/ext/README.md @@ -0,0 +1,5 @@ +Optional plugins for gRPC Core: Modules in this directory extend gRPC Core in +useful ways. All optional code belongs here. + +NOTE: The movement of code between lib and ext is an ongoing effort, so this +directory currently contains too much of the core library. diff --git a/src/core/ext/client_channel/channel_connectivity.c b/src/core/ext/client_channel/channel_connectivity.c index b10f444b63..dd70bc2c6c 100644 --- a/src/core/ext/client_channel/channel_connectivity.c +++ b/src/core/ext/client_channel/channel_connectivity.c @@ -76,6 +76,7 @@ typedef struct { gpr_mu mu; callback_phase phase; grpc_closure on_complete; + grpc_closure on_timeout; grpc_timer alarm; grpc_connectivity_state state; grpc_completion_queue *cq; @@ -200,6 +201,8 @@ void grpc_channel_watch_connectivity_state( gpr_mu_init(&w->mu); grpc_closure_init(&w->on_complete, watch_complete, w, grpc_schedule_on_exec_ctx); + grpc_closure_init(&w->on_timeout, timeout_complete, w, + grpc_schedule_on_exec_ctx); w->phase = WAITING; w->state = last_observed_state; w->cq = cq; @@ -208,7 +211,7 @@ void grpc_channel_watch_connectivity_state( grpc_timer_init(&exec_ctx, &w->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - timeout_complete, w, gpr_now(GPR_CLOCK_MONOTONIC)); + &w->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC)); if (client_channel_elem->filter == &grpc_client_channel_filter) { GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity"); diff --git a/src/core/ext/client_channel/subchannel.c b/src/core/ext/client_channel/subchannel.c index f8f48f2894..54764ea7f8 100644 --- a/src/core/ext/client_channel/subchannel.c +++ b/src/core/ext/client_channel/subchannel.c @@ -109,6 +109,9 @@ struct grpc_subchannel { /** callback for connection finishing */ grpc_closure connected; + /** callback for our alarm */ + grpc_closure on_alarm; + /** pollset_set tracking who's interested in a connection being setup */ grpc_pollset_set *pollset_set; @@ -483,7 +486,8 @@ static void maybe_start_connecting_locked(grpc_exec_ctx *exec_ctx, gpr_log(GPR_INFO, "Retry in %" PRId64 ".%09d seconds", time_til_next.tv_sec, time_til_next.tv_nsec); } - grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now); + grpc_closure_init(&c->on_alarm, on_alarm, c, grpc_schedule_on_exec_ctx); + grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, &c->on_alarm, now); } } diff --git a/src/core/ext/lb_policy/grpclb/grpclb.c b/src/core/ext/lb_policy/grpclb/grpclb.c index 390c6ff817..3cdd96e7ae 100644 --- a/src/core/ext/lb_policy/grpclb/grpclb.c +++ b/src/core/ext/lb_policy/grpclb/grpclb.c @@ -327,6 +327,9 @@ typedef struct glb_lb_policy { /* A response from the LB server has been received. Process it */ grpc_closure lb_on_response_received; + /* LB call retry timer callback. */ + grpc_closure lb_on_call_retry; + grpc_call *lb_call; /* streaming call to the LB server, */ grpc_metadata_array lb_initial_metadata_recv; /* initial MD from LB server */ @@ -1368,8 +1371,10 @@ static void lb_on_server_status_received(grpc_exec_ctx *exec_ctx, void *arg, } } GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "grpclb_retry_timer"); + grpc_closure_init(&glb_policy->lb_on_call_retry, lb_call_on_retry_timer, + glb_policy, grpc_schedule_on_exec_ctx); grpc_timer_init(exec_ctx, &glb_policy->lb_call_retry_timer, next_try, - lb_call_on_retry_timer, glb_policy, now); + &glb_policy->lb_on_call_retry, now); } gpr_mu_unlock(&glb_policy->mu); GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, diff --git a/src/core/ext/resolver/README.md b/src/core/ext/resolver/README.md new file mode 100644 index 0000000000..b0e234e96a --- /dev/null +++ b/src/core/ext/resolver/README.md @@ -0,0 +1,4 @@ +# Resolver + +Implementations of various name resolution schemes. +See the [naming spec](/doc/naming.md). diff --git a/src/core/ext/resolver/dns/native/dns_resolver.c b/src/core/ext/resolver/dns/native/dns_resolver.c index 124b16bbc3..bb2b012507 100644 --- a/src/core/ext/resolver/dns/native/dns_resolver.c +++ b/src/core/ext/resolver/dns/native/dns_resolver.c @@ -81,6 +81,7 @@ typedef struct { /** retry timer */ bool have_retry_timer; grpc_timer retry_timer; + grpc_closure on_retry; /** retry backoff state */ gpr_backoff backoff_state; @@ -199,8 +200,9 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg, } else { gpr_log(GPR_DEBUG, "retrying immediately"); } - grpc_timer_init(exec_ctx, &r->retry_timer, next_try, dns_on_retry_timer, r, - now); + grpc_closure_init(&r->on_retry, dns_on_retry_timer, r, + grpc_schedule_on_exec_ctx); + grpc_timer_init(exec_ctx, &r->retry_timer, next_try, &r->on_retry, now); } if (r->resolved_result != NULL) { grpc_channel_args_destroy(exec_ctx, r->resolved_result); diff --git a/src/core/ext/transport/README.md b/src/core/ext/transport/README.md new file mode 100644 index 0000000000..2290568784 --- /dev/null +++ b/src/core/ext/transport/README.md @@ -0,0 +1 @@ +Transports for gRPC diff --git a/src/core/ext/transport/chttp2/README.md b/src/core/ext/transport/chttp2/README.md new file mode 100644 index 0000000000..8880a47460 --- /dev/null +++ b/src/core/ext/transport/chttp2/README.md @@ -0,0 +1 @@ +CHTTP2 - gRPC's implementation of a HTTP2 based transport diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 0f762dbceb..1bf6dd4c28 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -47,6 +47,7 @@ #include "src/core/ext/transport/chttp2/transport/http2_errors.h" #include "src/core/ext/transport/chttp2/transport/internal.h" #include "src/core/ext/transport/chttp2/transport/status_conversion.h" +#include "src/core/ext/transport/chttp2/transport/varint.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/workqueue.h" @@ -1677,8 +1678,9 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, if (optional_message != NULL) { size_t msg_len = strlen(optional_message); - GPR_ASSERT(msg_len < 127); - message_pfx = grpc_slice_malloc(15); + GPR_ASSERT(msg_len <= UINT32_MAX); + uint32_t msg_len_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)msg_len, 0); + message_pfx = grpc_slice_malloc(14 + msg_len_len); p = GRPC_SLICE_START_PTR(message_pfx); *p++ = 0x40; *p++ = 12; /* len(grpc-message) */ @@ -1694,7 +1696,9 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, *p++ = 'a'; *p++ = 'g'; *p++ = 'e'; - *p++ = (uint8_t)msg_len; + GRPC_CHTTP2_WRITE_VARINT((uint32_t)msg_len, 0, 0, p, + (uint32_t)msg_len_len); + p += msg_len_len; GPR_ASSERT(p == GRPC_SLICE_END_PTR(message_pfx)); len += (uint32_t)GRPC_SLICE_LENGTH(message_pfx); len += (uint32_t)msg_len; diff --git a/src/core/lib/README.md b/src/core/lib/README.md new file mode 100644 index 0000000000..69b6bce2d9 --- /dev/null +++ b/src/core/lib/README.md @@ -0,0 +1,6 @@ +Required elements of gRPC Core: Each module in this directory is required to +build gRPC. If it's possible to envisage a configuration where code is not +required, then that code belongs in ext/ instead. + +NOTE: The movement of code between lib and ext is an ongoing effort, so this +directory currently contains too much of the core library. diff --git a/src/core/lib/channel/README.md b/src/core/lib/channel/README.md new file mode 100644 index 0000000000..2dfcfe6e66 --- /dev/null +++ b/src/core/lib/channel/README.md @@ -0,0 +1,4 @@ +# Channel + +Provides channel/call stack implementation, and implementation of common filters +for that implementation. diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/lib/channel/deadline_filter.c index 8dd6d099e1..a45a4d4b82 100644 --- a/src/core/lib/channel/deadline_filter.c +++ b/src/core/lib/channel/deadline_filter.c @@ -83,8 +83,11 @@ static void start_timer_if_needed_locked(grpc_exec_ctx* exec_ctx, // Take a reference to the call stack, to be owned by the timer. GRPC_CALL_STACK_REF(deadline_state->call_stack, "deadline_timer"); deadline_state->timer_pending = true; - grpc_timer_init(exec_ctx, &deadline_state->timer, deadline, timer_callback, - elem, gpr_now(GPR_CLOCK_MONOTONIC)); + grpc_closure_init(&deadline_state->timer_callback, timer_callback, elem, + grpc_schedule_on_exec_ctx); + grpc_timer_init(exec_ctx, &deadline_state->timer, deadline, + &deadline_state->timer_callback, + gpr_now(GPR_CLOCK_MONOTONIC)); } } static void start_timer_if_needed(grpc_exec_ctx* exec_ctx, diff --git a/src/core/lib/channel/deadline_filter.h b/src/core/lib/channel/deadline_filter.h index 716a852565..bd2b84f79e 100644 --- a/src/core/lib/channel/deadline_filter.h +++ b/src/core/lib/channel/deadline_filter.h @@ -46,6 +46,7 @@ typedef struct grpc_deadline_state { bool timer_pending; // The deadline timer. grpc_timer timer; + grpc_closure timer_callback; // Closure to invoke when the call is complete. // We use this to cancel the timer. grpc_closure on_complete; diff --git a/src/core/lib/channel/handshaker.c b/src/core/lib/channel/handshaker.c index ff827527b3..c052ca5385 100644 --- a/src/core/lib/channel/handshaker.c +++ b/src/core/lib/channel/handshaker.c @@ -86,6 +86,7 @@ struct grpc_handshake_manager { grpc_tcp_server_acceptor* acceptor; // Deadline timer across all handshakers. grpc_timer deadline_timer; + grpc_closure on_timeout; // The final callback and user_data to invoke after the last handshaker. grpc_closure on_handshake_done; void* user_data; @@ -224,9 +225,11 @@ void grpc_handshake_manager_do_handshake( grpc_schedule_on_exec_ctx); // Start deadline timer, which owns a ref. gpr_ref(&mgr->refs); + grpc_closure_init(&mgr->on_timeout, on_timeout, mgr, + grpc_schedule_on_exec_ctx); grpc_timer_init(exec_ctx, &mgr->deadline_timer, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - on_timeout, mgr, gpr_now(GPR_CLOCK_MONOTONIC)); + &mgr->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC)); // Start first handshaker, which also owns a ref. gpr_ref(&mgr->refs); bool done = call_next_handshaker_locked(exec_ctx, mgr, GRPC_ERROR_NONE); diff --git a/src/core/lib/iomgr/README.md b/src/core/lib/iomgr/README.md new file mode 100644 index 0000000000..9b22b76ceb --- /dev/null +++ b/src/core/lib/iomgr/README.md @@ -0,0 +1,6 @@ +# iomgr + +Platform abstractions for I/O (mostly network). + +Provides abstractions over TCP/UDP I/O, file loading, polling, and concurrency +management for various operating systems. diff --git a/src/core/lib/iomgr/tcp_client_posix.c b/src/core/lib/iomgr/tcp_client_posix.c index c8237dc38f..9a77c92016 100644 --- a/src/core/lib/iomgr/tcp_client_posix.c +++ b/src/core/lib/iomgr/tcp_client_posix.c @@ -65,6 +65,7 @@ typedef struct { grpc_fd *fd; gpr_timespec deadline; grpc_timer alarm; + grpc_closure on_alarm; int refs; grpc_closure write_closure; grpc_pollset_set *interested_parties; @@ -352,9 +353,10 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx, } gpr_mu_lock(&ac->mu); + grpc_closure_init(&ac->on_alarm, tc_on_alarm, ac, grpc_schedule_on_exec_ctx); grpc_timer_init(exec_ctx, &ac->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - tc_on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC)); + &ac->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC)); grpc_fd_notify_on_write(exec_ctx, ac->fd, &ac->write_closure); gpr_mu_unlock(&ac->mu); diff --git a/src/core/lib/iomgr/tcp_client_uv.c b/src/core/lib/iomgr/tcp_client_uv.c index ed0de50fc1..5225a5402b 100644 --- a/src/core/lib/iomgr/tcp_client_uv.c +++ b/src/core/lib/iomgr/tcp_client_uv.c @@ -49,6 +49,7 @@ typedef struct grpc_uv_tcp_connect { uv_connect_t connect_req; grpc_timer alarm; + grpc_closure on_alarm; uv_tcp_t *tcp_handle; grpc_closure *closure; grpc_endpoint **endpoint; @@ -148,9 +149,11 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx, uv_tcp_connect(&connect->connect_req, connect->tcp_handle, (const struct sockaddr *)resolved_addr->addr, uv_tc_on_connect); + grpc_closure_init(&connect->on_alarm, uv_tc_on_alarm, connect, + grpc_schedule_on_exec_ctx); grpc_timer_init(exec_ctx, &connect->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - uv_tc_on_alarm, connect, gpr_now(GPR_CLOCK_MONOTONIC)); + &connect->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC)); } // overridden by api_fuzzer.c diff --git a/src/core/lib/iomgr/tcp_client_windows.c b/src/core/lib/iomgr/tcp_client_windows.c index 275258ebb5..1e84ec3a1e 100644 --- a/src/core/lib/iomgr/tcp_client_windows.c +++ b/src/core/lib/iomgr/tcp_client_windows.c @@ -58,6 +58,7 @@ typedef struct { grpc_winsocket *socket; gpr_timespec deadline; grpc_timer alarm; + grpc_closure on_alarm; char *addr_name; int refs; grpc_closure on_connect; @@ -229,7 +230,8 @@ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done, ac->resource_quota = resource_quota; grpc_closure_init(&ac->on_connect, on_connect, ac, grpc_schedule_on_exec_ctx); - grpc_timer_init(exec_ctx, &ac->alarm, deadline, on_alarm, ac, + grpc_closure_init(&ac->on_alarm, on_alarm, ac, grpc_schedule_on_exec_ctx); + grpc_timer_init(exec_ctx, &ac->alarm, deadline, &ac->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC)); grpc_socket_notify_on_write(exec_ctx, socket, &ac->on_connect); return; diff --git a/src/core/lib/iomgr/timer.h b/src/core/lib/iomgr/timer.h index 20fe98c4a7..d84a278b18 100644 --- a/src/core/lib/iomgr/timer.h +++ b/src/core/lib/iomgr/timer.h @@ -49,15 +49,15 @@ typedef struct grpc_timer grpc_timer; -/* Initialize *timer. When expired or canceled, timer_cb will be called with - *timer_cb_arg and error set to indicate if it expired (GRPC_ERROR_NONE) or - was canceled (GRPC_ERROR_CANCELLED). timer_cb is guaranteed to be called - exactly once, and application code should check the error to determine - how it was invoked. The application callback is also responsible for - maintaining information about when to free up any user-level state. */ +/* Initialize *timer. When expired or canceled, closure will be called with + error set to indicate if it expired (GRPC_ERROR_NONE) or was canceled + (GRPC_ERROR_CANCELLED). timer_cb is guaranteed to be called exactly once, and + application code should check the error to determine how it was invoked. The + application callback is also responsible for maintaining information about + when to free up any user-level state. */ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, - gpr_timespec deadline, grpc_iomgr_cb_func timer_cb, - void *timer_cb_arg, gpr_timespec now); + gpr_timespec deadline, grpc_closure *closure, + gpr_timespec now); /* Note that there is no timer destroy function. This is because the timer is a one-time occurrence with a guarantee that the callback will diff --git a/src/core/lib/iomgr/timer_generic.c b/src/core/lib/iomgr/timer_generic.c index ecd3b284dc..40c8351472 100644 --- a/src/core/lib/iomgr/timer_generic.c +++ b/src/core/lib/iomgr/timer_generic.c @@ -178,28 +178,27 @@ static void note_deadline_change(shard_type *shard) { } void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, - gpr_timespec deadline, grpc_iomgr_cb_func timer_cb, - void *timer_cb_arg, gpr_timespec now) { + gpr_timespec deadline, grpc_closure *closure, + gpr_timespec now) { int is_first_timer = 0; shard_type *shard = &g_shards[shard_idx(timer)]; GPR_ASSERT(deadline.clock_type == g_clock_type); GPR_ASSERT(now.clock_type == g_clock_type); - grpc_closure_init(&timer->closure, timer_cb, timer_cb_arg, - grpc_schedule_on_exec_ctx); + timer->closure = closure; timer->deadline = deadline; timer->triggered = 0; if (!g_initialized) { timer->triggered = 1; grpc_closure_sched( - exec_ctx, &timer->closure, + exec_ctx, timer->closure, GRPC_ERROR_CREATE("Attempt to create timer before initialization")); return; } if (gpr_time_cmp(deadline, now) <= 0) { timer->triggered = 1; - grpc_closure_sched(exec_ctx, &timer->closure, GRPC_ERROR_NONE); + grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_NONE); return; } @@ -251,7 +250,7 @@ void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) { shard_type *shard = &g_shards[shard_idx(timer)]; gpr_mu_lock(&shard->mu); if (!timer->triggered) { - grpc_closure_sched(exec_ctx, &timer->closure, GRPC_ERROR_CANCELLED); + grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_CANCELLED); timer->triggered = 1; if (timer->heap_index == INVALID_HEAP_INDEX) { list_remove(timer); @@ -317,7 +316,7 @@ static size_t pop_timers(grpc_exec_ctx *exec_ctx, shard_type *shard, grpc_timer *timer; gpr_mu_lock(&shard->mu); while ((timer = pop_one(shard, now))) { - grpc_closure_sched(exec_ctx, &timer->closure, GRPC_ERROR_REF(error)); + grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_REF(error)); n++; } *new_min_deadline = compute_min_deadline(shard); diff --git a/src/core/lib/iomgr/timer_generic.h b/src/core/lib/iomgr/timer_generic.h index e4494adb5f..9d901c7e68 100644 --- a/src/core/lib/iomgr/timer_generic.h +++ b/src/core/lib/iomgr/timer_generic.h @@ -43,7 +43,7 @@ struct grpc_timer { int triggered; struct grpc_timer *next; struct grpc_timer *prev; - grpc_closure closure; + grpc_closure *closure; }; #endif /* GRPC_CORE_LIB_IOMGR_TIMER_GENERIC_H */ diff --git a/src/core/lib/iomgr/timer_uv.c b/src/core/lib/iomgr/timer_uv.c index 00b835ffb8..fa2cdee964 100644 --- a/src/core/lib/iomgr/timer_uv.c +++ b/src/core/lib/iomgr/timer_uv.c @@ -55,21 +55,20 @@ void run_expired_timer(uv_timer_t *handle) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; GPR_ASSERT(!timer->triggered); timer->triggered = 1; - grpc_closure_sched(&exec_ctx, &timer->closure, GRPC_ERROR_NONE); + grpc_closure_sched(&exec_ctx, timer->closure, GRPC_ERROR_NONE); stop_uv_timer(handle); grpc_exec_ctx_finish(&exec_ctx); } void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, - gpr_timespec deadline, grpc_iomgr_cb_func timer_cb, - void *timer_cb_arg, gpr_timespec now) { + gpr_timespec deadline, grpc_closure *closure, + gpr_timespec now) { uint64_t timeout; uv_timer_t *uv_timer; - grpc_closure_init(&timer->closure, timer_cb, timer_cb_arg, - grpc_schedule_on_exec_ctx); + timer->closure = closure; if (gpr_time_cmp(deadline, now) <= 0) { timer->triggered = 1; - grpc_closure_sched(exec_ctx, &timer->closure, GRPC_ERROR_NONE); + grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_NONE); return; } timer->triggered = 0; @@ -84,7 +83,7 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) { if (!timer->triggered) { timer->triggered = 1; - grpc_closure_sched(exec_ctx, &timer->closure, GRPC_ERROR_CANCELLED); + grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_CANCELLED); stop_uv_timer((uv_timer_t *)timer->uv_timer); } } diff --git a/src/core/lib/iomgr/timer_uv.h b/src/core/lib/iomgr/timer_uv.h index 3de383ebd5..13cf8bd4fa 100644 --- a/src/core/lib/iomgr/timer_uv.h +++ b/src/core/lib/iomgr/timer_uv.h @@ -37,7 +37,7 @@ #include "src/core/lib/iomgr/exec_ctx.h" struct grpc_timer { - grpc_closure closure; + grpc_closure *closure; /* This is actually a uv_timer_t*, but we want to keep platform-specific types out of headers */ void *uv_timer; diff --git a/src/core/lib/surface/README.md b/src/core/lib/surface/README.md new file mode 100644 index 0000000000..74cbd71131 --- /dev/null +++ b/src/core/lib/surface/README.md @@ -0,0 +1,4 @@ +# Surface + +Surface provides the bulk of the gRPC Core public API, and translates it into +calls against core components. diff --git a/src/core/lib/surface/alarm.c b/src/core/lib/surface/alarm.c index aa9d60ee6a..e71c0ebfc5 100644 --- a/src/core/lib/surface/alarm.c +++ b/src/core/lib/surface/alarm.c @@ -38,6 +38,7 @@ struct grpc_alarm { grpc_timer alarm; + grpc_closure on_alarm; grpc_cq_completion completion; /** completion queue where events about this alarm will be posted */ grpc_completion_queue *cq; @@ -64,9 +65,11 @@ grpc_alarm *grpc_alarm_create(grpc_completion_queue *cq, gpr_timespec deadline, alarm->tag = tag; grpc_cq_begin_op(cq, tag); + grpc_closure_init(&alarm->on_alarm, alarm_cb, alarm, + grpc_schedule_on_exec_ctx); grpc_timer_init(&exec_ctx, &alarm->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - alarm_cb, alarm, gpr_now(GPR_CLOCK_MONOTONIC)); + &alarm->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC)); grpc_exec_ctx_finish(&exec_ctx); return alarm; } diff --git a/src/core/lib/transport/README.md b/src/core/lib/transport/README.md new file mode 100644 index 0000000000..e7e135edeb --- /dev/null +++ b/src/core/lib/transport/README.md @@ -0,0 +1,7 @@ +# Transport + +Common implementation details for gRPC Transports. + +Transports multiplex messages across some single connection. In ext/ there are +implementations atop [a custom http2 implementation](/src/core/ext/transport/chttp2/README.md) +and atop [cronet](/src/core/ext/transport/cronet/README.md). diff --git a/src/core/lib/tsi/README.md b/src/core/lib/tsi/README.md new file mode 100644 index 0000000000..3ca3c1ef38 --- /dev/null +++ b/src/core/lib/tsi/README.md @@ -0,0 +1,2 @@ +# Transport Security Interface +An abstraction library over crypto and auth modules (typically OpenSSL) diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js index 46ddecfb1f..75cfb41342 100644 --- a/src/node/interop/interop_client.js +++ b/src/node/interop/interop_client.js @@ -312,6 +312,9 @@ function customMetadata(client, done) { } }; var streaming_arg = { + response_parameters: [ + {size: 314159} + ], payload: { body: zeroBuffer(271828) } diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php index d201915d66..2acf5612c7 100755 --- a/src/php/tests/interop/interop_client.php +++ b/src/php/tests/interop/interop_client.php @@ -451,11 +451,22 @@ function customMetadata($stub) $streaming_request = new grpc\testing\StreamingOutputCallRequest(); $streaming_request->setPayload($payload); + $response_parameters = new grpc\testing\ResponseParameters(); + $response_parameters->setSize($response_len); + $streaming_request->getResponseParameters()[] = $response_parameters; $streaming_call->write($streaming_request); $streaming_call->writesDone(); + $result = $streaming_call->read(); hardAssertIfStatusOk($streaming_call->getStatus()); + $streaming_initial_metadata = $streaming_call->getMetadata(); + hardAssert(array_key_exists($ECHO_INITIAL_KEY, $streaming_initial_metadata), + 'Initial metadata does not contain expected key'); + hardAssert( + $streaming_initial_metadata[$ECHO_INITIAL_KEY][0] === $ECHO_INITIAL_VALUE, + 'Incorrect initial metadata value'); + $streaming_trailing_metadata = $streaming_call->getTrailingMetadata(); hardAssert(array_key_exists($ECHO_TRAILING_KEY, $streaming_trailing_metadata), diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py index 41e9163cd6..e8c6a99cb1 100644 --- a/src/python/grpcio/grpc/_channel.py +++ b/src/python/grpcio/grpc/_channel.py @@ -32,6 +32,7 @@ import sys import threading import time +import logging import grpc from grpc import _common @@ -197,7 +198,16 @@ def _consume_request_iterator( event_handler = _event_handler(state, call, None) def consume_request_iterator(): - for request in request_iterator: + while True: + try: + request = next(request_iterator) + except StopIteration: + break + except Exception as e: + logging.exception("Exception iterating requests!") + call.cancel() + _abort(state, grpc.StatusCode.UNKNOWN, "Exception iterating requests!") + return serialized_request = _common.serialize(request, request_serializer) with state.condition: if state.code is None and not state.cancelled: diff --git a/src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py b/src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py index c7bfeaeb95..43d6c971b5 100644 --- a/src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py +++ b/src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py @@ -75,7 +75,7 @@ class ReflectionServicerTest(unittest.TestCase): file_by_filename='i-donut-exist' ), ) - responses = tuple(self._stub.ServerReflectionInfo(requests)) + responses = tuple(self._stub.ServerReflectionInfo(iter(requests))) expected_responses = ( reflection_pb2.ServerReflectionResponse( valid_host='', @@ -93,7 +93,7 @@ class ReflectionServicerTest(unittest.TestCase): ) ), ) - self.assertEqual(expected_responses, responses) + self.assertSequenceEqual(expected_responses, responses) def testFileBySymbol(self): requests = ( @@ -104,7 +104,7 @@ class ReflectionServicerTest(unittest.TestCase): file_containing_symbol='i.donut.exist.co.uk.org.net.me.name.foo' ), ) - responses = tuple(self._stub.ServerReflectionInfo(requests)) + responses = tuple(self._stub.ServerReflectionInfo(iter(requests))) expected_responses = ( reflection_pb2.ServerReflectionResponse( valid_host='', @@ -122,7 +122,7 @@ class ReflectionServicerTest(unittest.TestCase): ) ), ) - self.assertEqual(expected_responses, responses) + self.assertSequenceEqual(expected_responses, responses) @unittest.skip('TODO(atash): implement file-containing-extension reflection ' '(see https://github.com/google/protobuf/issues/2248)') @@ -141,7 +141,7 @@ class ReflectionServicerTest(unittest.TestCase): ), ), ) - responses = tuple(self._stub.ServerReflectionInfo(requests)) + responses = tuple(self._stub.ServerReflectionInfo(iter(requests))) expected_responses = ( reflection_pb2.ServerReflectionResponse( valid_host='', @@ -159,7 +159,7 @@ class ReflectionServicerTest(unittest.TestCase): ) ), ) - self.assertEqual(expected_responses, responses) + self.assertSequenceEqual(expected_responses, responses) def testListServices(self): requests = ( @@ -167,7 +167,7 @@ class ReflectionServicerTest(unittest.TestCase): list_services='', ), ) - responses = tuple(self._stub.ServerReflectionInfo(requests)) + responses = tuple(self._stub.ServerReflectionInfo(iter(requests))) expected_responses = ( reflection_pb2.ServerReflectionResponse( valid_host='', @@ -179,7 +179,7 @@ class ReflectionServicerTest(unittest.TestCase): ) ), ) - self.assertEqual(expected_responses, responses) + self.assertSequenceEqual(expected_responses, responses) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json index 0109ee2173..70d965d3ca 100644 --- a/src/python/grpcio_tests/tests/tests.json +++ b/src/python/grpcio_tests/tests/tests.json @@ -28,6 +28,7 @@ "unit._empty_message_test.EmptyMessageTest", "unit._exit_test.ExitTest", "unit._invalid_metadata_test.InvalidMetadataTest", + "unit._invocation_defects_test.InvocationDefectsTest", "unit._metadata_code_details_test.MetadataCodeDetailsTest", "unit._metadata_test.MetadataTest", "unit._rpc_test.RPCTest", diff --git a/src/python/grpcio_tests/tests/unit/_compression_test.py b/src/python/grpcio_tests/tests/unit/_compression_test.py index 83b9109466..4d3f02e917 100644 --- a/src/python/grpcio_tests/tests/unit/_compression_test.py +++ b/src/python/grpcio_tests/tests/unit/_compression_test.py @@ -125,7 +125,7 @@ class CompressionTest(unittest.TestCase): compressed_channel = grpc.insecure_channel('localhost:%d' % self._port, options=[('grpc.default_compression_algorithm', 1)]) multi_callable = compressed_channel.stream_stream(_STREAM_STREAM) - call = multi_callable([request] * test_constants.STREAM_LENGTH) + call = multi_callable(iter([request] * test_constants.STREAM_LENGTH)) for response in call: self.assertEqual(request, response) diff --git a/src/python/grpcio_tests/tests/unit/_empty_message_test.py b/src/python/grpcio_tests/tests/unit/_empty_message_test.py index 131f6e9452..69f4689279 100644 --- a/src/python/grpcio_tests/tests/unit/_empty_message_test.py +++ b/src/python/grpcio_tests/tests/unit/_empty_message_test.py @@ -123,12 +123,12 @@ class EmptyMessageTest(unittest.TestCase): def testStreamUnary(self): response = self._channel.stream_unary(_STREAM_UNARY)( - [_REQUEST] * test_constants.STREAM_LENGTH) + iter([_REQUEST] * test_constants.STREAM_LENGTH)) self.assertEqual(_RESPONSE, response) def testStreamStream(self): response_iterator = self._channel.stream_stream(_STREAM_STREAM)( - [_REQUEST] * test_constants.STREAM_LENGTH) + iter([_REQUEST] * test_constants.STREAM_LENGTH)) self.assertSequenceEqual( [_RESPONSE] * test_constants.STREAM_LENGTH, list(response_iterator)) diff --git a/src/python/grpcio_tests/tests/unit/_exit_scenarios.py b/src/python/grpcio_tests/tests/unit/_exit_scenarios.py index b33802bf57..777527137f 100644 --- a/src/python/grpcio_tests/tests/unit/_exit_scenarios.py +++ b/src/python/grpcio_tests/tests/unit/_exit_scenarios.py @@ -240,7 +240,7 @@ if __name__ == '__main__': multi_callable = channel.stream_unary(method) future = multi_callable.future(infinite_request_iterator()) result, call = multi_callable.with_call( - [REQUEST] * test_constants.STREAM_LENGTH) + iter([REQUEST] * test_constants.STREAM_LENGTH)) elif (args.scenario == IN_FLIGHT_STREAM_STREAM_CALL or args.scenario == IN_FLIGHT_PARTIAL_STREAM_STREAM_CALL): multi_callable = channel.stream_stream(method) diff --git a/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py b/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py new file mode 100644 index 0000000000..4312679bb9 --- /dev/null +++ b/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py @@ -0,0 +1,247 @@ +# Copyright 2016, 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. + +import itertools +import threading +import unittest +from concurrent import futures + +import grpc +from grpc.framework.foundation import logging_pool + +from tests.unit.framework.common import test_constants +from tests.unit.framework.common import test_control + +_SERIALIZE_REQUEST = lambda bytestring: bytestring * 2 +_DESERIALIZE_REQUEST = lambda bytestring: bytestring[len(bytestring) // 2:] +_SERIALIZE_RESPONSE = lambda bytestring: bytestring * 3 +_DESERIALIZE_RESPONSE = lambda bytestring: bytestring[:len(bytestring) // 3] + +_UNARY_UNARY = '/test/UnaryUnary' +_UNARY_STREAM = '/test/UnaryStream' +_STREAM_UNARY = '/test/StreamUnary' +_STREAM_STREAM = '/test/StreamStream' + + +class _Callback(object): + def __init__(self): + self._condition = threading.Condition() + self._value = None + self._called = False + + def __call__(self, value): + with self._condition: + self._value = value + self._called = True + self._condition.notify_all() + + def value(self): + with self._condition: + while not self._called: + self._condition.wait() + return self._value + + +class _Handler(object): + def __init__(self, control): + self._control = control + + def handle_unary_unary(self, request, servicer_context): + self._control.control() + if servicer_context is not None: + servicer_context.set_trailing_metadata((('testkey', 'testvalue',),)) + return request + + def handle_unary_stream(self, request, servicer_context): + for _ in range(test_constants.STREAM_LENGTH): + self._control.control() + yield request + self._control.control() + if servicer_context is not None: + servicer_context.set_trailing_metadata((('testkey', 'testvalue',),)) + + def handle_stream_unary(self, request_iterator, servicer_context): + if servicer_context is not None: + servicer_context.invocation_metadata() + self._control.control() + response_elements = [] + for request in request_iterator: + self._control.control() + response_elements.append(request) + self._control.control() + if servicer_context is not None: + servicer_context.set_trailing_metadata((('testkey', 'testvalue',),)) + return b''.join(response_elements) + + def handle_stream_stream(self, request_iterator, servicer_context): + self._control.control() + if servicer_context is not None: + servicer_context.set_trailing_metadata((('testkey', 'testvalue',),)) + for request in request_iterator: + self._control.control() + yield request + self._control.control() + + +class _MethodHandler(grpc.RpcMethodHandler): + def __init__( + self, request_streaming, response_streaming, request_deserializer, + response_serializer, unary_unary, unary_stream, stream_unary, + stream_stream): + self.request_streaming = request_streaming + self.response_streaming = response_streaming + self.request_deserializer = request_deserializer + self.response_serializer = response_serializer + self.unary_unary = unary_unary + self.unary_stream = unary_stream + self.stream_unary = stream_unary + self.stream_stream = stream_stream + + +class _GenericHandler(grpc.GenericRpcHandler): + def __init__(self, handler): + self._handler = handler + + def service(self, handler_call_details): + if handler_call_details.method == _UNARY_UNARY: + return _MethodHandler( + False, False, None, None, self._handler.handle_unary_unary, None, + None, None) + elif handler_call_details.method == _UNARY_STREAM: + return _MethodHandler( + False, True, _DESERIALIZE_REQUEST, _SERIALIZE_RESPONSE, None, + self._handler.handle_unary_stream, None, None) + elif handler_call_details.method == _STREAM_UNARY: + return _MethodHandler( + True, False, _DESERIALIZE_REQUEST, _SERIALIZE_RESPONSE, None, None, + self._handler.handle_stream_unary, None) + elif handler_call_details.method == _STREAM_STREAM: + return _MethodHandler( + True, True, None, None, None, None, None, + self._handler.handle_stream_stream) + else: + return None + + +class FailAfterFewIterationsCounter(object): + def __init__(self, high, bytestring): + self._current = 0 + self._high = high + self._bytestring = bytestring + + def __iter__(self): + return self + + def __next__(self): + if self._current >= self._high: + raise Exception("This is a deliberate failure in a unit test.") + else: + self._current += 1 + return self._bytestring + + +def _unary_unary_multi_callable(channel): + return channel.unary_unary(_UNARY_UNARY) + + +def _unary_stream_multi_callable(channel): + return channel.unary_stream( + _UNARY_STREAM, + request_serializer=_SERIALIZE_REQUEST, + response_deserializer=_DESERIALIZE_RESPONSE) + + +def _stream_unary_multi_callable(channel): + return channel.stream_unary( + _STREAM_UNARY, + request_serializer=_SERIALIZE_REQUEST, + response_deserializer=_DESERIALIZE_RESPONSE) + + +def _stream_stream_multi_callable(channel): + return channel.stream_stream(_STREAM_STREAM) + + +class InvocationDefectsTest(unittest.TestCase): + def setUp(self): + self._control = test_control.PauseFailControl() + self._handler = _Handler(self._control) + self._server_pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY) + + self._server = grpc.server(self._server_pool) + port = self._server.add_insecure_port('[::]:0') + self._server.add_generic_rpc_handlers((_GenericHandler(self._handler),)) + self._server.start() + + self._channel = grpc.insecure_channel('localhost:%d' % port) + + def tearDown(self): + self._server.stop(0) + + def testIterableStreamRequestBlockingUnaryResponse(self): + requests = [b'\x07\x08' for _ in range(test_constants.STREAM_LENGTH)] + multi_callable = _stream_unary_multi_callable(self._channel) + + with self.assertRaises(grpc.RpcError): + response = multi_callable( + requests, + metadata=(('test', 'IterableStreamRequestBlockingUnaryResponse'),)) + + def testIterableStreamRequestFutureUnaryResponse(self): + requests = [b'\x07\x08' for _ in range(test_constants.STREAM_LENGTH)] + multi_callable = _stream_unary_multi_callable(self._channel) + response_future = multi_callable.future( + requests, + metadata=( + ('test', 'IterableStreamRequestFutureUnaryResponse'),)) + + with self.assertRaises(grpc.RpcError): + response = response_future.result() + + def testIterableStreamRequestStreamResponse(self): + requests = [b'\x77\x58' for _ in range(test_constants.STREAM_LENGTH)] + multi_callable = _stream_stream_multi_callable(self._channel) + response_iterator = multi_callable( + requests, + metadata=(('test', 'IterableStreamRequestStreamResponse'),)) + + with self.assertRaises(grpc.RpcError): + next(response_iterator) + + def testIteratorStreamRequestStreamResponse(self): + requests_iterator = FailAfterFewIterationsCounter( + test_constants.STREAM_LENGTH // 2, b'\x07\x08') + multi_callable = _stream_stream_multi_callable(self._channel) + response_iterator = multi_callable( + requests_iterator, + metadata=(('test', 'IteratorStreamRequestStreamResponse'),)) + + with self.assertRaises(grpc.RpcError): + for _ in range(test_constants.STREAM_LENGTH // 2 + 1): + next(response_iterator) diff --git a/src/python/grpcio_tests/tests/unit/_metadata_test.py b/src/python/grpcio_tests/tests/unit/_metadata_test.py index da73476929..caba53ffcc 100644 --- a/src/python/grpcio_tests/tests/unit/_metadata_test.py +++ b/src/python/grpcio_tests/tests/unit/_metadata_test.py @@ -193,7 +193,7 @@ class MetadataTest(unittest.TestCase): def testStreamUnary(self): multi_callable = self._channel.stream_unary(_STREAM_UNARY) unused_response, call = multi_callable.with_call( - [_REQUEST] * test_constants.STREAM_LENGTH, + iter([_REQUEST] * test_constants.STREAM_LENGTH), metadata=_CLIENT_METADATA) self.assertTrue(test_common.metadata_transmitted( _SERVER_INITIAL_METADATA, call.initial_metadata())) @@ -202,7 +202,7 @@ class MetadataTest(unittest.TestCase): def testStreamStream(self): multi_callable = self._channel.stream_stream(_STREAM_STREAM) - call = multi_callable([_REQUEST] * test_constants.STREAM_LENGTH, + call = multi_callable(iter([_REQUEST] * test_constants.STREAM_LENGTH), metadata=_CLIENT_METADATA) self.assertTrue(test_common.metadata_transmitted( _SERVER_INITIAL_METADATA, call.initial_metadata())) |