mirror of https://github.com/grpc/grpc.git
commit
75b53d6a5d
183 changed files with 16106 additions and 5359 deletions
@ -0,0 +1,283 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/channel/subchannel_call_holder.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
|
||||
#include "src/core/profiling/timers.h" |
||||
|
||||
#define GET_CALL(holder) \ |
||||
((grpc_subchannel_call *)(gpr_atm_acq_load(&(holder)->subchannel_call))) |
||||
|
||||
#define CANCELLED_CALL ((grpc_subchannel_call *)1) |
||||
|
||||
static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *holder, |
||||
int success); |
||||
static void call_ready(grpc_exec_ctx *exec_ctx, void *holder, int success); |
||||
static void retry_ops(grpc_exec_ctx *exec_ctx, void *retry_ops_args, |
||||
int success); |
||||
|
||||
static void add_waiting_locked(grpc_subchannel_call_holder *holder, |
||||
grpc_transport_stream_op *op); |
||||
static void fail_locked(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder); |
||||
static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder); |
||||
|
||||
void grpc_subchannel_call_holder_init( |
||||
grpc_subchannel_call_holder *holder, |
||||
grpc_subchannel_call_holder_pick_subchannel pick_subchannel, |
||||
void *pick_subchannel_arg) { |
||||
gpr_atm_rel_store(&holder->subchannel_call, 0); |
||||
holder->pick_subchannel = pick_subchannel; |
||||
holder->pick_subchannel_arg = pick_subchannel_arg; |
||||
gpr_mu_init(&holder->mu); |
||||
holder->subchannel = NULL; |
||||
holder->waiting_ops = NULL; |
||||
holder->waiting_ops_count = 0; |
||||
holder->waiting_ops_capacity = 0; |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; |
||||
} |
||||
|
||||
void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder) { |
||||
grpc_subchannel_call *call = GET_CALL(holder); |
||||
if (call != NULL && call != CANCELLED_CALL) { |
||||
GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "holder"); |
||||
} |
||||
GPR_ASSERT(holder->creation_phase == |
||||
GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING); |
||||
gpr_mu_destroy(&holder->mu); |
||||
GPR_ASSERT(holder->waiting_ops_count == 0); |
||||
gpr_free(holder->waiting_ops); |
||||
} |
||||
|
||||
void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder, |
||||
grpc_transport_stream_op *op) { |
||||
/* try to (atomically) get the call */ |
||||
grpc_subchannel_call *call = GET_CALL(holder); |
||||
GPR_TIMER_BEGIN("grpc_subchannel_call_holder_perform_op", 0); |
||||
if (call == CANCELLED_CALL) { |
||||
grpc_transport_stream_op_finish_with_failure(exec_ctx, op); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
return; |
||||
} |
||||
if (call != NULL) { |
||||
grpc_subchannel_call_process_op(exec_ctx, call, op); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
return; |
||||
} |
||||
/* we failed; lock and figure out what to do */ |
||||
gpr_mu_lock(&holder->mu); |
||||
retry: |
||||
/* need to recheck that another thread hasn't set the call */ |
||||
call = GET_CALL(holder); |
||||
if (call == CANCELLED_CALL) { |
||||
gpr_mu_unlock(&holder->mu); |
||||
grpc_transport_stream_op_finish_with_failure(exec_ctx, op); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
return; |
||||
} |
||||
if (call != NULL) { |
||||
gpr_mu_unlock(&holder->mu); |
||||
grpc_subchannel_call_process_op(exec_ctx, call, op); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
return; |
||||
} |
||||
/* if this is a cancellation, then we can raise our cancelled flag */ |
||||
if (op->cancel_with_status != GRPC_STATUS_OK) { |
||||
if (!gpr_atm_rel_cas(&holder->subchannel_call, 0, 1)) { |
||||
goto retry; |
||||
} else { |
||||
switch (holder->creation_phase) { |
||||
case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING: |
||||
fail_locked(exec_ctx, holder); |
||||
break; |
||||
case GRPC_SUBCHANNEL_CALL_HOLDER_CREATING_CALL: |
||||
grpc_subchannel_cancel_create_call(exec_ctx, holder->subchannel, |
||||
&holder->subchannel_call); |
||||
break; |
||||
case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL: |
||||
holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg, NULL, |
||||
&holder->subchannel, NULL); |
||||
break; |
||||
} |
||||
gpr_mu_unlock(&holder->mu); |
||||
grpc_transport_stream_op_finish_with_failure(exec_ctx, op); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
return; |
||||
} |
||||
} |
||||
/* if we don't have a subchannel, try to get one */ |
||||
if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING && |
||||
holder->subchannel == NULL && op->send_initial_metadata != NULL) { |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL; |
||||
grpc_closure_init(&holder->next_step, subchannel_ready, holder); |
||||
if (holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg, |
||||
op->send_initial_metadata, &holder->subchannel, |
||||
&holder->next_step)) { |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; |
||||
} |
||||
} |
||||
/* if we've got a subchannel, then let's ask it to create a call */ |
||||
if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING && |
||||
holder->subchannel != NULL) { |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_CREATING_CALL; |
||||
grpc_closure_init(&holder->next_step, call_ready, holder); |
||||
if (grpc_subchannel_create_call(exec_ctx, holder->subchannel, |
||||
holder->pollset, &holder->subchannel_call, |
||||
&holder->next_step)) { |
||||
/* got one immediately - continue the op (and any waiting ops) */ |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; |
||||
retry_waiting_locked(exec_ctx, holder); |
||||
goto retry; |
||||
} |
||||
} |
||||
/* nothing to be done but wait */ |
||||
add_waiting_locked(holder, op); |
||||
gpr_mu_unlock(&holder->mu); |
||||
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); |
||||
} |
||||
|
||||
static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, int success) { |
||||
grpc_subchannel_call_holder *holder = arg; |
||||
grpc_subchannel_call *call; |
||||
gpr_mu_lock(&holder->mu); |
||||
GPR_ASSERT(holder->creation_phase == |
||||
GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL); |
||||
call = GET_CALL(holder); |
||||
GPR_ASSERT(call == NULL || call == CANCELLED_CALL); |
||||
if (holder->subchannel == NULL) { |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; |
||||
fail_locked(exec_ctx, holder); |
||||
} else { |
||||
grpc_closure_init(&holder->next_step, call_ready, holder); |
||||
if (grpc_subchannel_create_call(exec_ctx, holder->subchannel, |
||||
holder->pollset, &holder->subchannel_call, |
||||
&holder->next_step)) { |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; |
||||
/* got one immediately - continue the op (and any waiting ops) */ |
||||
retry_waiting_locked(exec_ctx, holder); |
||||
} |
||||
} |
||||
gpr_mu_unlock(&holder->mu); |
||||
} |
||||
|
||||
static void call_ready(grpc_exec_ctx *exec_ctx, void *arg, int success) { |
||||
grpc_subchannel_call_holder *holder = arg; |
||||
GPR_TIMER_BEGIN("call_ready", 0); |
||||
gpr_mu_lock(&holder->mu); |
||||
GPR_ASSERT(holder->creation_phase == |
||||
GRPC_SUBCHANNEL_CALL_HOLDER_CREATING_CALL); |
||||
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; |
||||
if (GET_CALL(holder) != NULL) { |
||||
retry_waiting_locked(exec_ctx, holder); |
||||
} else { |
||||
fail_locked(exec_ctx, holder); |
||||
} |
||||
gpr_mu_unlock(&holder->mu); |
||||
GPR_TIMER_END("call_ready", 0); |
||||
} |
||||
|
||||
typedef struct { |
||||
grpc_transport_stream_op *ops; |
||||
size_t nops; |
||||
grpc_subchannel_call *call; |
||||
} retry_ops_args; |
||||
|
||||
static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder) { |
||||
retry_ops_args *a = gpr_malloc(sizeof(*a)); |
||||
a->ops = holder->waiting_ops; |
||||
a->nops = holder->waiting_ops_count; |
||||
a->call = GET_CALL(holder); |
||||
if (a->call == CANCELLED_CALL) { |
||||
gpr_free(a); |
||||
fail_locked(exec_ctx, holder); |
||||
return; |
||||
} |
||||
holder->waiting_ops = NULL; |
||||
holder->waiting_ops_count = 0; |
||||
holder->waiting_ops_capacity = 0; |
||||
GRPC_SUBCHANNEL_CALL_REF(a->call, "retry_ops"); |
||||
grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(retry_ops, a), 1); |
||||
} |
||||
|
||||
static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, int success) { |
||||
retry_ops_args *a = args; |
||||
size_t i; |
||||
for (i = 0; i < a->nops; i++) { |
||||
grpc_subchannel_call_process_op(exec_ctx, a->call, &a->ops[i]); |
||||
} |
||||
GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, a->call, "retry_ops"); |
||||
gpr_free(a->ops); |
||||
gpr_free(a); |
||||
} |
||||
|
||||
static void add_waiting_locked(grpc_subchannel_call_holder *holder, |
||||
grpc_transport_stream_op *op) { |
||||
GPR_TIMER_BEGIN("add_waiting_locked", 0); |
||||
if (holder->waiting_ops_count == holder->waiting_ops_capacity) { |
||||
holder->waiting_ops_capacity = GPR_MAX(3, 2 * holder->waiting_ops_capacity); |
||||
holder->waiting_ops = |
||||
gpr_realloc(holder->waiting_ops, holder->waiting_ops_capacity * |
||||
sizeof(*holder->waiting_ops)); |
||||
} |
||||
holder->waiting_ops[holder->waiting_ops_count++] = *op; |
||||
GPR_TIMER_END("add_waiting_locked", 0); |
||||
} |
||||
|
||||
static void fail_locked(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder) { |
||||
size_t i; |
||||
for (i = 0; i < holder->waiting_ops_count; i++) { |
||||
grpc_exec_ctx_enqueue(exec_ctx, holder->waiting_ops[i].on_complete, 0); |
||||
grpc_exec_ctx_enqueue(exec_ctx, holder->waiting_ops[i].recv_message_ready, |
||||
0); |
||||
} |
||||
holder->waiting_ops_count = 0; |
||||
} |
||||
|
||||
char *grpc_subchannel_call_holder_get_peer(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder, |
||||
grpc_channel *master) { |
||||
grpc_subchannel_call *subchannel_call = GET_CALL(holder); |
||||
|
||||
if (subchannel_call) { |
||||
return grpc_subchannel_call_get_peer(exec_ctx, subchannel_call); |
||||
} else { |
||||
return grpc_channel_get_target(master); |
||||
} |
||||
} |
@ -0,0 +1,98 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CHANNEL_SUBCHANNEL_CALL_HOLDER_H |
||||
#define GRPC_INTERNAL_CORE_CHANNEL_SUBCHANNEL_CALL_HOLDER_H |
||||
|
||||
#include "src/core/client_config/subchannel.h" |
||||
|
||||
/** Pick a subchannel for grpc_subchannel_call_holder;
|
||||
Return 1 if subchannel is available immediately (in which case on_ready |
||||
should not be called), or 0 otherwise (in which case on_ready should be |
||||
called when the subchannel is available) */ |
||||
typedef int (*grpc_subchannel_call_holder_pick_subchannel)( |
||||
grpc_exec_ctx *exec_ctx, void *arg, grpc_metadata_batch *initial_metadata, |
||||
grpc_subchannel **subchannel, grpc_closure *on_ready); |
||||
|
||||
typedef enum { |
||||
GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING, |
||||
GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL, |
||||
GRPC_SUBCHANNEL_CALL_HOLDER_CREATING_CALL |
||||
} grpc_subchannel_call_holder_creation_phase; |
||||
|
||||
/** Wrapper for holding a pointer to grpc_subchannel_call, and the
|
||||
associated machinery to create such a pointer. |
||||
Handles queueing of stream ops until a call object is ready, waiting |
||||
for initial metadata before trying to create a call object, |
||||
and handling cancellation gracefully. |
||||
|
||||
Both the channel and uchannel filter use this as their call_data. */ |
||||
typedef struct grpc_subchannel_call_holder { |
||||
/** either 0 for no call, 1 for cancelled, or a pointer to a
|
||||
grpc_subchannel_call */ |
||||
gpr_atm subchannel_call; |
||||
/** Helper function to choose the subchannel on which to create
|
||||
the call object. Channel filter delegates to the load |
||||
balancing policy (once it's ready); uchannel returns |
||||
immediately */ |
||||
grpc_subchannel_call_holder_pick_subchannel pick_subchannel; |
||||
void *pick_subchannel_arg; |
||||
|
||||
gpr_mu mu; |
||||
|
||||
grpc_subchannel_call_holder_creation_phase creation_phase; |
||||
grpc_subchannel *subchannel; |
||||
grpc_pollset *pollset; |
||||
|
||||
grpc_transport_stream_op *waiting_ops; |
||||
size_t waiting_ops_count; |
||||
size_t waiting_ops_capacity; |
||||
|
||||
grpc_closure next_step; |
||||
} grpc_subchannel_call_holder; |
||||
|
||||
void grpc_subchannel_call_holder_init( |
||||
grpc_subchannel_call_holder *holder, |
||||
grpc_subchannel_call_holder_pick_subchannel pick_subchannel, |
||||
void *pick_subchannel_arg); |
||||
void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder); |
||||
|
||||
void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder, |
||||
grpc_transport_stream_op *op); |
||||
char *grpc_subchannel_call_holder_get_peer(grpc_exec_ctx *exec_ctx, |
||||
grpc_subchannel_call_holder *holder, |
||||
grpc_channel *master); |
||||
|
||||
#endif |
@ -1,97 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/surface/byte_buffer_queue.h" |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/useful.h> |
||||
|
||||
static void bba_destroy(grpc_bbq_array *array, size_t start_pos) { |
||||
size_t i; |
||||
for (i = start_pos; i < array->count; i++) { |
||||
grpc_byte_buffer_destroy(array->data[i]); |
||||
} |
||||
gpr_free(array->data); |
||||
} |
||||
|
||||
/* Append an operation to an array, expanding as needed */ |
||||
static void bba_push(grpc_bbq_array *a, grpc_byte_buffer *buffer) { |
||||
if (a->count == a->capacity) { |
||||
a->capacity = GPR_MAX(a->capacity * 2, 8); |
||||
a->data = gpr_realloc(a->data, sizeof(grpc_byte_buffer *) * a->capacity); |
||||
} |
||||
a->data[a->count++] = buffer; |
||||
} |
||||
|
||||
void grpc_bbq_destroy(grpc_byte_buffer_queue *q) { |
||||
bba_destroy(&q->filling, 0); |
||||
bba_destroy(&q->draining, q->drain_pos); |
||||
} |
||||
|
||||
int grpc_bbq_empty(grpc_byte_buffer_queue *q) { |
||||
return (q->drain_pos == q->draining.count && q->filling.count == 0); |
||||
} |
||||
|
||||
void grpc_bbq_push(grpc_byte_buffer_queue *q, grpc_byte_buffer *buffer) { |
||||
q->bytes += grpc_byte_buffer_length(buffer); |
||||
bba_push(&q->filling, buffer); |
||||
} |
||||
|
||||
void grpc_bbq_flush(grpc_byte_buffer_queue *q) { |
||||
grpc_byte_buffer *bb; |
||||
while ((bb = grpc_bbq_pop(q))) { |
||||
grpc_byte_buffer_destroy(bb); |
||||
} |
||||
} |
||||
|
||||
size_t grpc_bbq_bytes(grpc_byte_buffer_queue *q) { return q->bytes; } |
||||
|
||||
grpc_byte_buffer *grpc_bbq_pop(grpc_byte_buffer_queue *q) { |
||||
grpc_bbq_array temp_array; |
||||
grpc_byte_buffer *out; |
||||
|
||||
if (q->drain_pos == q->draining.count) { |
||||
if (q->filling.count == 0) { |
||||
return NULL; |
||||
} |
||||
q->draining.count = 0; |
||||
q->drain_pos = 0; |
||||
/* swap arrays */ |
||||
temp_array = q->filling; |
||||
q->filling = q->draining; |
||||
q->draining = temp_array; |
||||
} |
||||
|
||||
out = q->draining.data[q->drain_pos++]; |
||||
q->bytes -= grpc_byte_buffer_length(out); |
||||
return out; |
||||
} |
@ -1,62 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_SURFACE_BYTE_BUFFER_QUEUE_H |
||||
#define GRPC_INTERNAL_CORE_SURFACE_BYTE_BUFFER_QUEUE_H |
||||
|
||||
#include <grpc/byte_buffer.h> |
||||
|
||||
/* TODO(ctiller): inline an element or two into this struct to avoid per-call
|
||||
allocations */ |
||||
typedef struct { |
||||
grpc_byte_buffer **data; |
||||
size_t count; |
||||
size_t capacity; |
||||
} grpc_bbq_array; |
||||
|
||||
/* should be initialized by zeroing memory */ |
||||
typedef struct { |
||||
size_t drain_pos; |
||||
grpc_bbq_array filling; |
||||
grpc_bbq_array draining; |
||||
size_t bytes; |
||||
} grpc_byte_buffer_queue; |
||||
|
||||
void grpc_bbq_destroy(grpc_byte_buffer_queue *q); |
||||
grpc_byte_buffer *grpc_bbq_pop(grpc_byte_buffer_queue *q); |
||||
void grpc_bbq_flush(grpc_byte_buffer_queue *q); |
||||
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 */ |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,76 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/transport/byte_stream.h" |
||||
|
||||
#include <stdlib.h> |
||||
|
||||
#include <grpc/support/log.h> |
||||
|
||||
int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx, |
||||
grpc_byte_stream *byte_stream, gpr_slice *slice, |
||||
size_t max_size_hint, grpc_closure *on_complete) { |
||||
return byte_stream->next(exec_ctx, byte_stream, slice, max_size_hint, |
||||
on_complete); |
||||
} |
||||
|
||||
void grpc_byte_stream_destroy(grpc_byte_stream *byte_stream) { |
||||
byte_stream->destroy(byte_stream); |
||||
} |
||||
|
||||
/* slice_buffer_stream */ |
||||
|
||||
static int slice_buffer_stream_next(grpc_exec_ctx *exec_ctx, |
||||
grpc_byte_stream *byte_stream, |
||||
gpr_slice *slice, size_t max_size_hint, |
||||
grpc_closure *on_complete) { |
||||
grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream; |
||||
GPR_ASSERT(stream->cursor < stream->backing_buffer->count); |
||||
*slice = gpr_slice_ref(stream->backing_buffer->slices[stream->cursor]); |
||||
stream->cursor++; |
||||
return 1; |
||||
} |
||||
|
||||
static void slice_buffer_stream_destroy(grpc_byte_stream *byte_stream) {} |
||||
|
||||
void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream, |
||||
gpr_slice_buffer *slice_buffer, |
||||
gpr_uint32 flags) { |
||||
GPR_ASSERT(slice_buffer->length <= GPR_UINT32_MAX); |
||||
stream->base.length = (gpr_uint32)slice_buffer->length; |
||||
stream->base.flags = flags; |
||||
stream->base.next = slice_buffer_stream_next; |
||||
stream->base.destroy = slice_buffer_stream_destroy; |
||||
stream->backing_buffer = slice_buffer; |
||||
stream->cursor = 0; |
||||
} |
@ -0,0 +1,88 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_TRANSPORT_BYTE_STREAM_H |
||||
#define GRPC_INTERNAL_CORE_TRANSPORT_BYTE_STREAM_H |
||||
|
||||
#include "src/core/iomgr/exec_ctx.h" |
||||
#include <grpc/support/slice_buffer.h> |
||||
|
||||
/** Internal bit flag for grpc_begin_message's \a flags signaling the use of
|
||||
* compression for the message */ |
||||
#define GRPC_WRITE_INTERNAL_COMPRESS (0x80000000u) |
||||
/** Mask of all valid internal flags. */ |
||||
#define GRPC_WRITE_INTERNAL_USED_MASK (GRPC_WRITE_INTERNAL_COMPRESS) |
||||
|
||||
struct grpc_byte_stream; |
||||
typedef struct grpc_byte_stream grpc_byte_stream; |
||||
|
||||
struct grpc_byte_stream { |
||||
gpr_uint32 length; |
||||
gpr_uint32 flags; |
||||
int (*next)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream, |
||||
gpr_slice *slice, size_t max_size_hint, |
||||
grpc_closure *on_complete); |
||||
void (*destroy)(grpc_byte_stream *byte_stream); |
||||
}; |
||||
|
||||
/* returns 1 if the bytes are available immediately (in which case
|
||||
* on_complete will not be called), 0 if the bytes will be available |
||||
* asynchronously. |
||||
* |
||||
* on entry, *remaining can be set as a hint as to the maximum number |
||||
* of bytes that would be acceptable to read. |
||||
* |
||||
* fills *buffer, *length, *remaining with the bytes, length of bytes |
||||
* and length of data remaining to be read before either returning 1 |
||||
* or calling on_complete. |
||||
* |
||||
* once a slice is returned into *slice, it is owned by the caller. |
||||
*/ |
||||
int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx, |
||||
grpc_byte_stream *byte_stream, gpr_slice *slice, |
||||
size_t max_size_hint, grpc_closure *on_complete); |
||||
|
||||
void grpc_byte_stream_destroy(grpc_byte_stream *byte_stream); |
||||
|
||||
/* grpc_byte_stream that wraps a slice buffer */ |
||||
typedef struct grpc_slice_buffer_stream { |
||||
grpc_byte_stream base; |
||||
gpr_slice_buffer *backing_buffer; |
||||
size_t cursor; |
||||
} grpc_slice_buffer_stream; |
||||
|
||||
void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream, |
||||
gpr_slice_buffer *slice_buffer, |
||||
gpr_uint32 flags); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_TRANSPORT_BYTE_STREAM_H */ |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,183 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "test/core/end2end/end2end_tests.h" |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
|
||||
#include "src/core/support/string.h" |
||||
#include <grpc/byte_buffer.h> |
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/time.h> |
||||
#include <grpc/support/useful.h> |
||||
#include "test/core/end2end/cq_verifier.h" |
||||
|
||||
enum { TIMEOUT = 200000 }; |
||||
|
||||
static void *tag(gpr_intptr t) { return (void *)t; } |
||||
|
||||
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, |
||||
const char *test_name, |
||||
grpc_channel_args *client_args, |
||||
grpc_channel_args *server_args) { |
||||
grpc_end2end_test_fixture f; |
||||
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); |
||||
f = config.create_fixture(client_args, server_args); |
||||
config.init_client(&f, client_args); |
||||
config.init_server(&f, server_args); |
||||
return f; |
||||
} |
||||
|
||||
static gpr_timespec n_seconds_time(int n) { |
||||
return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(n); |
||||
} |
||||
|
||||
static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); } |
||||
|
||||
static void drain_cq(grpc_completion_queue *cq) { |
||||
grpc_event ev; |
||||
do { |
||||
ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL); |
||||
} while (ev.type != GRPC_QUEUE_SHUTDOWN); |
||||
} |
||||
|
||||
static void shutdown_server(grpc_end2end_test_fixture *f) { |
||||
if (!f->server) return; |
||||
grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000)); |
||||
GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000), |
||||
GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), |
||||
NULL).type == GRPC_OP_COMPLETE); |
||||
grpc_server_destroy(f->server); |
||||
f->server = NULL; |
||||
} |
||||
|
||||
static void shutdown_client(grpc_end2end_test_fixture *f) { |
||||
if (!f->client) return; |
||||
grpc_channel_destroy(f->client); |
||||
f->client = NULL; |
||||
} |
||||
|
||||
static void end_test(grpc_end2end_test_fixture *f) { |
||||
shutdown_server(f); |
||||
shutdown_client(f); |
||||
|
||||
grpc_completion_queue_shutdown(f->cq); |
||||
drain_cq(f->cq); |
||||
grpc_completion_queue_destroy(f->cq); |
||||
} |
||||
|
||||
static void simple_request_body(grpc_end2end_test_fixture f, size_t num_ops) { |
||||
grpc_call *c; |
||||
gpr_timespec deadline = five_seconds_time(); |
||||
cq_verifier *cqv = cq_verifier_create(f.cq); |
||||
grpc_op ops[6]; |
||||
grpc_op *op; |
||||
grpc_metadata_array initial_metadata_recv; |
||||
grpc_metadata_array trailing_metadata_recv; |
||||
grpc_status_code status; |
||||
grpc_call_error error; |
||||
char *details = NULL; |
||||
size_t details_capacity = 0; |
||||
|
||||
gpr_log(GPR_DEBUG, "test with %d ops", num_ops); |
||||
|
||||
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, |
||||
"/foo", "foo.test.google.fr:1234", deadline, |
||||
NULL); |
||||
GPR_ASSERT(c); |
||||
|
||||
grpc_metadata_array_init(&initial_metadata_recv); |
||||
grpc_metadata_array_init(&trailing_metadata_recv); |
||||
|
||||
op = ops; |
||||
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; |
||||
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; |
||||
op->data.recv_status_on_client.status = &status; |
||||
op->data.recv_status_on_client.status_details = &details; |
||||
op->data.recv_status_on_client.status_details_capacity = &details_capacity; |
||||
op->flags = 0; |
||||
op->reserved = NULL; |
||||
op++; |
||||
op->op = GRPC_OP_RECV_INITIAL_METADATA; |
||||
op->data.recv_initial_metadata = &initial_metadata_recv; |
||||
op->flags = 0; |
||||
op->reserved = NULL; |
||||
op++; |
||||
op->op = GRPC_OP_SEND_INITIAL_METADATA; |
||||
op->data.send_initial_metadata.count = 0; |
||||
op->flags = 0; |
||||
op->reserved = NULL; |
||||
op++; |
||||
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; |
||||
op->flags = 0; |
||||
op->reserved = NULL; |
||||
op++; |
||||
GPR_ASSERT(num_ops <= (size_t)(op - ops)); |
||||
error = grpc_call_start_batch(c, ops, num_ops, tag(1), NULL); |
||||
GPR_ASSERT(GRPC_CALL_OK == error); |
||||
|
||||
grpc_call_cancel_with_status(c, GRPC_STATUS_UNIMPLEMENTED, "xyz", NULL); |
||||
|
||||
cq_expect_completion(cqv, tag(1), 1); |
||||
cq_verify(cqv); |
||||
|
||||
GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED); |
||||
GPR_ASSERT(0 == strcmp(details, "xyz")); |
||||
|
||||
gpr_free(details); |
||||
grpc_metadata_array_destroy(&initial_metadata_recv); |
||||
grpc_metadata_array_destroy(&trailing_metadata_recv); |
||||
|
||||
grpc_call_destroy(c); |
||||
|
||||
cq_verifier_destroy(cqv); |
||||
} |
||||
|
||||
static void test_invoke_simple_request(grpc_end2end_test_config config, size_t num_ops) { |
||||
grpc_end2end_test_fixture f; |
||||
|
||||
f = begin_test(config, "test_invoke_simple_request", NULL, NULL); |
||||
simple_request_body(f, num_ops); |
||||
end_test(&f); |
||||
config.tear_down_data(&f); |
||||
} |
||||
|
||||
void grpc_end2end_tests(grpc_end2end_test_config config) { |
||||
size_t i; |
||||
for (i = 1; i <= 4; i++) { |
||||
test_invoke_simple_request(config, i); |
||||
} |
||||
} |
@ -0,0 +1,180 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "test/core/end2end/end2end_tests.h" |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
|
||||
#include "src/core/support/string.h" |
||||
#include <grpc/byte_buffer.h> |
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/time.h> |
||||
#include <grpc/support/useful.h> |
||||
#include "test/core/end2end/cq_verifier.h" |
||||
|
||||
enum { TIMEOUT = 200000 }; |
||||
|
||||
static void *tag(gpr_intptr t) { return (void *)t; } |
||||
|
||||
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, |
||||
const char *test_name, |
||||
grpc_channel_args *client_args, |
||||
grpc_channel_args *server_args) { |
||||
grpc_end2end_test_fixture f; |
||||
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); |
||||
f = config.create_fixture(client_args, server_args); |
||||
config.init_client(&f, client_args); |
||||
config.init_server(&f, server_args); |
||||
return f; |
||||
} |
||||
|
||||
static gpr_timespec n_seconds_time(int n) { |
||||
return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(n); |
||||
} |
||||
|
||||
static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); } |
||||
|
||||
static void drain_cq(grpc_completion_queue *cq) { |
||||
grpc_event ev; |
||||
do { |
||||
ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL); |
||||
} while (ev.type != GRPC_QUEUE_SHUTDOWN); |
||||
} |
||||
|
||||
static void shutdown_server(grpc_end2end_test_fixture *f) { |
||||
if (!f->server) return; |
||||
grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000)); |
||||
GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000), |
||||
GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), |
||||
NULL).type == GRPC_OP_COMPLETE); |
||||
grpc_server_destroy(f->server); |
||||
f->server = NULL; |
||||
} |
||||
|
||||
static void shutdown_client(grpc_end2end_test_fixture *f) { |
||||
if (!f->client) return; |
||||
grpc_channel_destroy(f->client); |
||||
f->client = NULL; |
||||
} |
||||
|
||||
static void end_test(grpc_end2end_test_fixture *f) { |
||||
shutdown_server(f); |
||||
shutdown_client(f); |
||||
|
||||
grpc_completion_queue_shutdown(f->cq); |
||||
drain_cq(f->cq); |
||||
grpc_completion_queue_destroy(f->cq); |
||||
} |
||||
|
||||
static void simple_request_body(grpc_end2end_test_fixture f, size_t num_ops) { |
||||
grpc_call *c; |
||||
gpr_timespec deadline = gpr_inf_past(GPR_CLOCK_REALTIME); |
||||
cq_verifier *cqv = cq_verifier_create(f.cq); |
||||
grpc_op ops[6]; |
||||
grpc_op *op; |
||||
grpc_metadata_array initial_metadata_recv; |
||||
grpc_metadata_array trailing_metadata_recv; |
||||
grpc_status_code status; |
||||
grpc_call_error error; |
||||
char *details = NULL; |
||||
size_t details_capacity = 0; |
||||
|
||||
gpr_log(GPR_DEBUG, "test with %d ops", num_ops); |
||||
|
||||
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, |
||||
"/foo", "foo.test.google.fr:1234", deadline, |
||||
NULL); |
||||
GPR_ASSERT(c); |
||||
|
||||
grpc_metadata_array_init(&initial_metadata_recv); |
||||
grpc_metadata_array_init(&trailing_metadata_recv); |
||||
|
||||
op = ops; |
||||
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; |
||||
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; |
||||
op->data.recv_status_on_client.status = &status; |
||||
op->data.recv_status_on_client.status_details = &details; |
||||
op->data.recv_status_on_client.status_details_capacity = &details_capacity; |
||||
op->flags = 0; |
||||
op->reserved = NULL; |
||||
op++; |
||||
op->op = GRPC_OP_RECV_INITIAL_METADATA; |
||||
op->data.recv_initial_metadata = &initial_metadata_recv; |
||||
op->flags = 0; |
||||
op->reserved = NULL; |
||||
op++; |
||||
op->op = GRPC_OP_SEND_INITIAL_METADATA; |
||||
op->data.send_initial_metadata.count = 0; |
||||
op->flags = 0; |
||||
op->reserved = NULL; |
||||
op++; |
||||
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; |
||||
op->flags = 0; |
||||
op->reserved = NULL; |
||||
op++; |
||||
GPR_ASSERT(num_ops <= (size_t)(op - ops)); |
||||
error = grpc_call_start_batch(c, ops, num_ops, tag(1), NULL); |
||||
GPR_ASSERT(GRPC_CALL_OK == error); |
||||
|
||||
cq_expect_completion(cqv, tag(1), 1); |
||||
cq_verify(cqv); |
||||
|
||||
GPR_ASSERT(status == GRPC_STATUS_DEADLINE_EXCEEDED); |
||||
|
||||
gpr_free(details); |
||||
grpc_metadata_array_destroy(&initial_metadata_recv); |
||||
grpc_metadata_array_destroy(&trailing_metadata_recv); |
||||
|
||||
grpc_call_destroy(c); |
||||
|
||||
cq_verifier_destroy(cqv); |
||||
} |
||||
|
||||
static void test_invoke_simple_request(grpc_end2end_test_config config, size_t num_ops) { |
||||
grpc_end2end_test_fixture f; |
||||
|
||||
f = begin_test(config, "test_invoke_simple_request", NULL, NULL); |
||||
simple_request_body(f, num_ops); |
||||
end_test(&f); |
||||
config.tear_down_data(&f); |
||||
} |
||||
|
||||
void grpc_end2end_tests(grpc_end2end_test_config config) { |
||||
size_t i; |
||||
for (i = 1; i <= 4; i++) { |
||||
test_invoke_simple_request(config, i); |
||||
} |
||||
} |
@ -0,0 +1,200 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/transport/chttp2/hpack_encoder.h" |
||||
|
||||
#include <stdio.h> |
||||
|
||||
#include "src/core/support/string.h" |
||||
#include "src/core/transport/chttp2/hpack_parser.h" |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
#include "test/core/util/parse_hexstring.h" |
||||
#include "test/core/util/slice_splitter.h" |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
#define TEST(x) run_test(x, #x) |
||||
|
||||
grpc_mdctx *g_mdctx; |
||||
grpc_chttp2_hpack_compressor g_compressor; |
||||
int g_failure = 0; |
||||
|
||||
void **to_delete = NULL; |
||||
size_t num_to_delete = 0; |
||||
size_t cap_to_delete = 0; |
||||
|
||||
/* verify that the output generated by encoding the stream matches the
|
||||
hexstring passed in */ |
||||
static void verify(size_t window_available, int eof, size_t expect_window_used, |
||||
const char *expected, size_t nheaders, ...) { |
||||
gpr_slice_buffer output; |
||||
gpr_slice merged; |
||||
gpr_slice expect = parse_hexstring(expected); |
||||
size_t i; |
||||
va_list l; |
||||
grpc_linked_mdelem *e = gpr_malloc(sizeof(*e) * nheaders); |
||||
grpc_metadata_batch b; |
||||
|
||||
grpc_metadata_batch_init(&b); |
||||
|
||||
va_start(l, nheaders); |
||||
for (i = 0; i < nheaders; i++) { |
||||
char *key = va_arg(l, char *); |
||||
char *value = va_arg(l, char *); |
||||
if (i) { |
||||
e[i - 1].next = &e[i]; |
||||
e[i].prev = &e[i - 1]; |
||||
} |
||||
e[i].md = grpc_mdelem_from_strings(g_mdctx, key, value); |
||||
} |
||||
e[0].prev = NULL; |
||||
e[nheaders - 1].next = NULL; |
||||
va_end(l); |
||||
|
||||
b.list.head = &e[0]; |
||||
b.list.tail = &e[nheaders - 1]; |
||||
|
||||
if (cap_to_delete == num_to_delete) { |
||||
cap_to_delete = GPR_MAX(2 * cap_to_delete, 1000); |
||||
to_delete = gpr_realloc(to_delete, sizeof(*to_delete) * cap_to_delete); |
||||
} |
||||
to_delete[num_to_delete++] = e; |
||||
|
||||
gpr_slice_buffer_init(&output); |
||||
|
||||
grpc_chttp2_encode_header(&g_compressor, 0xdeadbeef, &b, eof, &output); |
||||
merged = grpc_slice_merge(output.slices, output.count); |
||||
gpr_slice_buffer_destroy(&output); |
||||
grpc_metadata_batch_destroy(&b); |
||||
|
||||
if (0 != gpr_slice_cmp(merged, expect)) { |
||||
char *expect_str = gpr_dump_slice(expect, GPR_DUMP_HEX | GPR_DUMP_ASCII); |
||||
char *got_str = gpr_dump_slice(merged, GPR_DUMP_HEX | GPR_DUMP_ASCII); |
||||
gpr_log(GPR_ERROR, "mismatched output for %s", expected); |
||||
gpr_log(GPR_ERROR, "EXPECT: %s", expect_str); |
||||
gpr_log(GPR_ERROR, "GOT: %s", got_str); |
||||
gpr_free(expect_str); |
||||
gpr_free(got_str); |
||||
g_failure = 1; |
||||
} |
||||
|
||||
gpr_slice_unref(merged); |
||||
gpr_slice_unref(expect); |
||||
} |
||||
|
||||
static void test_basic_headers(void) { |
||||
int i; |
||||
|
||||
verify(0, 0, 0, "000005 0104 deadbeef 40 0161 0161", 1, "a", "a"); |
||||
verify(0, 0, 0, "000001 0104 deadbeef be", 1, "a", "a"); |
||||
verify(0, 0, 0, "000001 0104 deadbeef be", 1, "a", "a"); |
||||
verify(0, 0, 0, "000006 0104 deadbeef be 40 0162 0163", 2, "a", "a", "b", |
||||
"c"); |
||||
verify(0, 0, 0, "000002 0104 deadbeef bf be", 2, "a", "a", "b", "c"); |
||||
verify(0, 0, 0, "000004 0104 deadbeef 7f 00 0164", 1, "a", "d"); |
||||
|
||||
/* flush out what's there to make a few values look very popular */ |
||||
for (i = 0; i < 350; i++) { |
||||
verify(0, 0, 0, "000003 0104 deadbeef c0 bf be", 3, "a", "a", "b", "c", "a", |
||||
"d"); |
||||
} |
||||
|
||||
verify(0, 0, 0, "000006 0104 deadbeef c0 00 016b 0176", 2, "a", "a", "k", |
||||
"v"); |
||||
/* this could be 000004 0104 deadbeef 0f 30 0176 also */ |
||||
verify(0, 0, 0, "000004 0104 deadbeef 0f 2f 0176", 1, "a", "v"); |
||||
} |
||||
|
||||
static void encode_int_to_str(int i, char *p) { |
||||
p[0] = (char)('a' + i % 26); |
||||
i /= 26; |
||||
GPR_ASSERT(i < 26); |
||||
p[1] = (char)('a' + i); |
||||
p[2] = 0; |
||||
} |
||||
|
||||
static void test_decode_table_overflow(void) { |
||||
int i; |
||||
char key[3], value[3]; |
||||
char *expect; |
||||
|
||||
for (i = 0; i < 114; i++) { |
||||
encode_int_to_str(i, key); |
||||
encode_int_to_str(i + 1, value); |
||||
|
||||
if (i + 61 >= 127) { |
||||
gpr_asprintf(&expect, |
||||
"000009 0104 deadbeef ff%02x 40 02%02x%02x 02%02x%02x", |
||||
i + 61 - 127, key[0], key[1], value[0], value[1]); |
||||
} else if (i > 0) { |
||||
gpr_asprintf(&expect, |
||||
"000008 0104 deadbeef %02x 40 02%02x%02x 02%02x%02x", |
||||
0x80 + 61 + i, key[0], key[1], value[0], value[1]); |
||||
} else { |
||||
gpr_asprintf(&expect, "000007 0104 deadbeef 40 02%02x%02x 02%02x%02x", |
||||
key[0], key[1], value[0], value[1]); |
||||
} |
||||
|
||||
if (i > 0) { |
||||
verify(0, 0, 0, expect, 2, "aa", "ba", key, value); |
||||
} else { |
||||
verify(0, 0, 0, expect, 1, key, value); |
||||
} |
||||
gpr_free(expect); |
||||
} |
||||
|
||||
/* if the above passes, then we must have just knocked this pair out of the
|
||||
decoder stack, and so we'll be forced to re-encode it */ |
||||
verify(0, 0, 0, "000007 0104 deadbeef 40 026161 026261", 1, "aa", "ba"); |
||||
} |
||||
|
||||
static void run_test(void (*test)(), const char *name) { |
||||
gpr_log(GPR_INFO, "RUN TEST: %s", name); |
||||
g_mdctx = grpc_mdctx_create_with_seed(0); |
||||
grpc_chttp2_hpack_compressor_init(&g_compressor, g_mdctx); |
||||
test(); |
||||
grpc_chttp2_hpack_compressor_destroy(&g_compressor); |
||||
grpc_mdctx_unref(g_mdctx); |
||||
} |
||||
|
||||
int main(int argc, char **argv) { |
||||
size_t i; |
||||
grpc_test_init(argc, argv); |
||||
TEST(test_basic_headers); |
||||
TEST(test_decode_table_overflow); |
||||
for (i = 0; i < num_to_delete; i++) { |
||||
gpr_free(to_delete[i]); |
||||
} |
||||
return g_failure; |
||||
} |
@ -1,359 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/transport/chttp2/stream_encoder.h" |
||||
|
||||
#include <stdio.h> |
||||
|
||||
#include "src/core/support/string.h" |
||||
#include "src/core/transport/chttp2/hpack_parser.h" |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
#include "test/core/util/parse_hexstring.h" |
||||
#include "test/core/util/slice_splitter.h" |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
#define TEST(x) run_test(x, #x) |
||||
|
||||
grpc_mdctx *g_mdctx; |
||||
grpc_chttp2_hpack_compressor g_compressor; |
||||
int g_failure = 0; |
||||
grpc_stream_op_buffer g_sopb; |
||||
|
||||
void **to_delete = NULL; |
||||
size_t num_to_delete = 0; |
||||
size_t cap_to_delete = 0; |
||||
|
||||
static gpr_slice create_test_slice(size_t length) { |
||||
gpr_slice slice = gpr_slice_malloc(length); |
||||
size_t i; |
||||
for (i = 0; i < length; i++) { |
||||
GPR_SLICE_START_PTR(slice)[i] = (gpr_uint8)i; |
||||
} |
||||
return slice; |
||||
} |
||||
|
||||
/* verify that the output generated by encoding the stream matches the
|
||||
hexstring passed in */ |
||||
static void verify_sopb(size_t window_available, int eof, |
||||
size_t expect_window_used, const char *expected) { |
||||
gpr_slice_buffer output; |
||||
grpc_stream_op_buffer encops; |
||||
gpr_slice merged; |
||||
gpr_slice expect = parse_hexstring(expected); |
||||
gpr_slice_buffer_init(&output); |
||||
grpc_sopb_init(&encops); |
||||
GPR_ASSERT(expect_window_used == |
||||
grpc_chttp2_preencode(g_sopb.ops, &g_sopb.nops, |
||||
(gpr_uint32)window_available, &encops)); |
||||
grpc_chttp2_encode(encops.ops, encops.nops, eof, 0xdeadbeef, &g_compressor, |
||||
&output); |
||||
encops.nops = 0; |
||||
merged = grpc_slice_merge(output.slices, output.count); |
||||
gpr_slice_buffer_destroy(&output); |
||||
grpc_sopb_destroy(&encops); |
||||
|
||||
if (0 != gpr_slice_cmp(merged, expect)) { |
||||
char *expect_str = gpr_dump_slice(expect, GPR_DUMP_HEX | GPR_DUMP_ASCII); |
||||
char *got_str = gpr_dump_slice(merged, GPR_DUMP_HEX | GPR_DUMP_ASCII); |
||||
gpr_log(GPR_ERROR, "mismatched output for %s", expected); |
||||
gpr_log(GPR_ERROR, "EXPECT: %s", expect_str); |
||||
gpr_log(GPR_ERROR, "GOT: %s", got_str); |
||||
gpr_free(expect_str); |
||||
gpr_free(got_str); |
||||
g_failure = 1; |
||||
} |
||||
|
||||
gpr_slice_unref(merged); |
||||
gpr_slice_unref(expect); |
||||
} |
||||
|
||||
static void test_small_data_framing(void) { |
||||
grpc_sopb_add_no_op(&g_sopb); |
||||
verify_sopb(10, 0, 0, ""); |
||||
|
||||
grpc_sopb_add_slice(&g_sopb, create_test_slice(3)); |
||||
verify_sopb(10, 0, 3, "000003 0000 deadbeef 000102"); |
||||
|
||||
grpc_sopb_add_slice(&g_sopb, create_test_slice(4)); |
||||
verify_sopb(10, 0, 4, "000004 0000 deadbeef 00010203"); |
||||
|
||||
grpc_sopb_add_slice(&g_sopb, create_test_slice(3)); |
||||
grpc_sopb_add_slice(&g_sopb, create_test_slice(4)); |
||||
verify_sopb(10, 0, 7, "000007 0000 deadbeef 000102 00010203"); |
||||
|
||||
grpc_sopb_add_slice(&g_sopb, create_test_slice(0)); |
||||
grpc_sopb_add_slice(&g_sopb, create_test_slice(0)); |
||||
grpc_sopb_add_slice(&g_sopb, create_test_slice(0)); |
||||
grpc_sopb_add_slice(&g_sopb, create_test_slice(0)); |
||||
grpc_sopb_add_slice(&g_sopb, create_test_slice(3)); |
||||
verify_sopb(10, 0, 3, "000003 0000 deadbeef 000102"); |
||||
|
||||
verify_sopb(10, 1, 0, "000000 0001 deadbeef"); |
||||
|
||||
grpc_sopb_add_begin_message(&g_sopb, 255, 0); |
||||
verify_sopb(10, 0, 5, "000005 0000 deadbeef 00000000ff"); |
||||
} |
||||
|
||||
static void add_sopb_headers(size_t n, ...) { |
||||
size_t i; |
||||
grpc_metadata_batch b; |
||||
va_list l; |
||||
grpc_linked_mdelem *e = gpr_malloc(sizeof(*e) * n); |
||||
|
||||
grpc_metadata_batch_init(&b); |
||||
|
||||
va_start(l, n); |
||||
for (i = 0; i < n; i++) { |
||||
char *key = va_arg(l, char *); |
||||
char *value = va_arg(l, char *); |
||||
if (i) { |
||||
e[i - 1].next = &e[i]; |
||||
e[i].prev = &e[i - 1]; |
||||
} |
||||
e[i].md = grpc_mdelem_from_strings(g_mdctx, key, value); |
||||
} |
||||
e[0].prev = NULL; |
||||
e[n - 1].next = NULL; |
||||
va_end(l); |
||||
|
||||
b.list.head = &e[0]; |
||||
b.list.tail = &e[n - 1]; |
||||
|
||||
if (cap_to_delete == num_to_delete) { |
||||
cap_to_delete = GPR_MAX(2 * cap_to_delete, 1000); |
||||
to_delete = gpr_realloc(to_delete, sizeof(*to_delete) * cap_to_delete); |
||||
} |
||||
to_delete[num_to_delete++] = e; |
||||
|
||||
grpc_sopb_add_metadata(&g_sopb, b); |
||||
} |
||||
|
||||
static void test_basic_headers(void) { |
||||
int i; |
||||
|
||||
add_sopb_headers(1, "a", "a"); |
||||
verify_sopb(0, 0, 0, "000005 0104 deadbeef 40 0161 0161"); |
||||
|
||||
add_sopb_headers(1, "a", "a"); |
||||
verify_sopb(0, 0, 0, "000001 0104 deadbeef be"); |
||||
|
||||
add_sopb_headers(1, "a", "a"); |
||||
verify_sopb(0, 0, 0, "000001 0104 deadbeef be"); |
||||
|
||||
add_sopb_headers(2, "a", "a", "b", "c"); |
||||
verify_sopb(0, 0, 0, "000006 0104 deadbeef be 40 0162 0163"); |
||||
|
||||
add_sopb_headers(2, "a", "a", "b", "c"); |
||||
verify_sopb(0, 0, 0, "000002 0104 deadbeef bf be"); |
||||
|
||||
add_sopb_headers(1, "a", "d"); |
||||
verify_sopb(0, 0, 0, "000004 0104 deadbeef 7f 00 0164"); |
||||
|
||||
/* flush out what's there to make a few values look very popular */ |
||||
for (i = 0; i < 350; i++) { |
||||
add_sopb_headers(3, "a", "a", "b", "c", "a", "d"); |
||||
verify_sopb(0, 0, 0, "000003 0104 deadbeef c0 bf be"); |
||||
} |
||||
|
||||
add_sopb_headers(2, "a", "a", "k", "v"); |
||||
verify_sopb(0, 0, 0, "000006 0104 deadbeef c0 00 016b 0176"); |
||||
|
||||
add_sopb_headers(1, "a", "v"); |
||||
/* this could be 000004 0104 deadbeef 0f 30 0176 also */ |
||||
verify_sopb(0, 0, 0, "000004 0104 deadbeef 0f 2f 0176"); |
||||
} |
||||
|
||||
static void encode_int_to_str(int i, char *p) { |
||||
p[0] = (char)('a' + i % 26); |
||||
i /= 26; |
||||
GPR_ASSERT(i < 26); |
||||
p[1] = (char)('a' + i); |
||||
p[2] = 0; |
||||
} |
||||
|
||||
static void test_decode_table_overflow(void) { |
||||
int i; |
||||
char key[3], value[3]; |
||||
char *expect; |
||||
|
||||
for (i = 0; i < 114; i++) { |
||||
if (i > 0) { |
||||
add_sopb_headers(1, "aa", "ba"); |
||||
} |
||||
|
||||
encode_int_to_str(i, key); |
||||
encode_int_to_str(i + 1, value); |
||||
|
||||
if (i + 61 >= 127) { |
||||
gpr_asprintf(&expect, |
||||
"000002 0104 deadbeef ff%02x 000007 0104 deadbeef 40 " |
||||
"02%02x%02x 02%02x%02x", |
||||
i + 61 - 127, key[0], key[1], value[0], value[1]); |
||||
} else if (i > 0) { |
||||
gpr_asprintf(&expect, |
||||
"000001 0104 deadbeef %02x 000007 0104 deadbeef 40 " |
||||
"02%02x%02x 02%02x%02x", |
||||
0x80 + 61 + i, key[0], key[1], value[0], value[1]); |
||||
} else { |
||||
gpr_asprintf(&expect, "000007 0104 deadbeef 40 02%02x%02x 02%02x%02x", |
||||
key[0], key[1], value[0], value[1]); |
||||
} |
||||
|
||||
add_sopb_headers(1, key, value); |
||||
verify_sopb(0, 0, 0, expect); |
||||
gpr_free(expect); |
||||
} |
||||
|
||||
/* if the above passes, then we must have just knocked this pair out of the
|
||||
decoder stack, and so we'll be forced to re-encode it */ |
||||
add_sopb_headers(1, "aa", "ba"); |
||||
verify_sopb(0, 0, 0, "000007 0104 deadbeef 40 026161 026261"); |
||||
} |
||||
|
||||
static void randstr(char *p, int bufsz) { |
||||
int i; |
||||
int len = 1 + rand() % bufsz; |
||||
for (i = 0; i < len; i++) { |
||||
p[i] = (char)('a' + rand() % 26); |
||||
} |
||||
p[len] = 0; |
||||
} |
||||
|
||||
typedef struct { |
||||
char key[300]; |
||||
char value[300]; |
||||
int got_hdr; |
||||
} test_decode_random_header_state; |
||||
|
||||
static void chk_hdr(void *p, grpc_mdelem *el) { |
||||
test_decode_random_header_state *st = p; |
||||
GPR_ASSERT(0 == gpr_slice_str_cmp(el->key->slice, st->key)); |
||||
GPR_ASSERT(0 == gpr_slice_str_cmp(el->value->slice, st->value)); |
||||
st->got_hdr = 1; |
||||
GRPC_MDELEM_UNREF(el); |
||||
} |
||||
|
||||
static void test_decode_random_headers_inner(int max_len) { |
||||
int i; |
||||
test_decode_random_header_state st; |
||||
gpr_slice_buffer output; |
||||
gpr_slice merged; |
||||
grpc_stream_op_buffer encops; |
||||
grpc_chttp2_hpack_parser parser; |
||||
|
||||
grpc_chttp2_hpack_parser_init(&parser, g_mdctx); |
||||
grpc_sopb_init(&encops); |
||||
|
||||
gpr_log(GPR_INFO, "max_len = %d", max_len); |
||||
|
||||
for (i = 0; i < 10000; i++) { |
||||
randstr(st.key, max_len); |
||||
randstr(st.value, max_len); |
||||
|
||||
add_sopb_headers(1, st.key, st.value); |
||||
gpr_slice_buffer_init(&output); |
||||
GPR_ASSERT(0 == |
||||
grpc_chttp2_preencode(g_sopb.ops, &g_sopb.nops, 0, &encops)); |
||||
grpc_chttp2_encode(encops.ops, encops.nops, 0, 0xdeadbeef, &g_compressor, |
||||
&output); |
||||
encops.nops = 0; |
||||
merged = grpc_slice_merge(output.slices, output.count); |
||||
gpr_slice_buffer_destroy(&output); |
||||
|
||||
st.got_hdr = 0; |
||||
parser.on_header = chk_hdr; |
||||
parser.on_header_user_data = &st; |
||||
grpc_chttp2_hpack_parser_parse(&parser, GPR_SLICE_START_PTR(merged) + 9, |
||||
GPR_SLICE_END_PTR(merged)); |
||||
GPR_ASSERT(st.got_hdr); |
||||
|
||||
gpr_slice_unref(merged); |
||||
} |
||||
|
||||
grpc_chttp2_hpack_parser_destroy(&parser); |
||||
grpc_sopb_destroy(&encops); |
||||
} |
||||
|
||||
#define DECL_TEST_DECODE_RANDOM_HEADERS(n) \ |
||||
static void test_decode_random_headers_##n(void) { \
|
||||
test_decode_random_headers_inner(n); \
|
||||
} \
|
||||
int keeps_formatting_correct_##n |
||||
|
||||
DECL_TEST_DECODE_RANDOM_HEADERS(1); |
||||
DECL_TEST_DECODE_RANDOM_HEADERS(2); |
||||
DECL_TEST_DECODE_RANDOM_HEADERS(3); |
||||
DECL_TEST_DECODE_RANDOM_HEADERS(5); |
||||
DECL_TEST_DECODE_RANDOM_HEADERS(8); |
||||
DECL_TEST_DECODE_RANDOM_HEADERS(13); |
||||
DECL_TEST_DECODE_RANDOM_HEADERS(21); |
||||
DECL_TEST_DECODE_RANDOM_HEADERS(34); |
||||
DECL_TEST_DECODE_RANDOM_HEADERS(55); |
||||
DECL_TEST_DECODE_RANDOM_HEADERS(89); |
||||
DECL_TEST_DECODE_RANDOM_HEADERS(144); |
||||
|
||||
static void run_test(void (*test)(), const char *name) { |
||||
gpr_log(GPR_INFO, "RUN TEST: %s", name); |
||||
g_mdctx = grpc_mdctx_create_with_seed(0); |
||||
grpc_chttp2_hpack_compressor_init(&g_compressor, g_mdctx); |
||||
grpc_sopb_init(&g_sopb); |
||||
test(); |
||||
grpc_chttp2_hpack_compressor_destroy(&g_compressor); |
||||
grpc_mdctx_unref(g_mdctx); |
||||
grpc_sopb_destroy(&g_sopb); |
||||
} |
||||
|
||||
int main(int argc, char **argv) { |
||||
size_t i; |
||||
grpc_test_init(argc, argv); |
||||
TEST(test_small_data_framing); |
||||
TEST(test_basic_headers); |
||||
TEST(test_decode_table_overflow); |
||||
TEST(test_decode_random_headers_1); |
||||
TEST(test_decode_random_headers_2); |
||||
TEST(test_decode_random_headers_3); |
||||
TEST(test_decode_random_headers_5); |
||||
TEST(test_decode_random_headers_8); |
||||
TEST(test_decode_random_headers_13); |
||||
TEST(test_decode_random_headers_21); |
||||
TEST(test_decode_random_headers_34); |
||||
TEST(test_decode_random_headers_55); |
||||
TEST(test_decode_random_headers_89); |
||||
TEST(test_decode_random_headers_144); |
||||
for (i = 0; i < num_to_delete; i++) { |
||||
gpr_free(to_delete[i]); |
||||
} |
||||
return g_failure; |
||||
} |
@ -1,116 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/transport/stream_op.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/log.h> |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
static void assert_slices_equal(gpr_slice a, gpr_slice b) { |
||||
GPR_ASSERT(a.refcount == b.refcount); |
||||
if (a.refcount) { |
||||
GPR_ASSERT(a.data.refcounted.bytes == b.data.refcounted.bytes); |
||||
GPR_ASSERT(a.data.refcounted.length == b.data.refcounted.length); |
||||
} else { |
||||
GPR_ASSERT(a.data.inlined.length == b.data.inlined.length); |
||||
GPR_ASSERT(0 == memcmp(a.data.inlined.bytes, b.data.inlined.bytes, |
||||
a.data.inlined.length)); |
||||
} |
||||
} |
||||
|
||||
int main(int argc, char **argv) { |
||||
/* some basic test data */ |
||||
gpr_slice test_slice_1 = gpr_slice_malloc(1); |
||||
gpr_slice test_slice_2 = gpr_slice_malloc(2); |
||||
gpr_slice test_slice_3 = gpr_slice_malloc(3); |
||||
gpr_slice test_slice_4 = gpr_slice_malloc(4); |
||||
unsigned i; |
||||
|
||||
grpc_stream_op_buffer buf; |
||||
grpc_stream_op_buffer buf2; |
||||
|
||||
grpc_test_init(argc, argv); |
||||
/* initialize one of our buffers */ |
||||
grpc_sopb_init(&buf); |
||||
/* it should start out empty */ |
||||
GPR_ASSERT(buf.nops == 0); |
||||
|
||||
/* add some data to the buffer */ |
||||
grpc_sopb_add_begin_message(&buf, 1, 2); |
||||
grpc_sopb_add_slice(&buf, test_slice_1); |
||||
grpc_sopb_add_slice(&buf, test_slice_2); |
||||
grpc_sopb_add_slice(&buf, test_slice_3); |
||||
grpc_sopb_add_slice(&buf, test_slice_4); |
||||
grpc_sopb_add_no_op(&buf); |
||||
|
||||
/* verify that the data went in ok */ |
||||
GPR_ASSERT(buf.nops == 6); |
||||
GPR_ASSERT(buf.ops[0].type == GRPC_OP_BEGIN_MESSAGE); |
||||
GPR_ASSERT(buf.ops[0].data.begin_message.length == 1); |
||||
GPR_ASSERT(buf.ops[0].data.begin_message.flags == 2); |
||||
GPR_ASSERT(buf.ops[1].type == GRPC_OP_SLICE); |
||||
assert_slices_equal(buf.ops[1].data.slice, test_slice_1); |
||||
GPR_ASSERT(buf.ops[2].type == GRPC_OP_SLICE); |
||||
assert_slices_equal(buf.ops[2].data.slice, test_slice_2); |
||||
GPR_ASSERT(buf.ops[3].type == GRPC_OP_SLICE); |
||||
assert_slices_equal(buf.ops[3].data.slice, test_slice_3); |
||||
GPR_ASSERT(buf.ops[4].type == GRPC_OP_SLICE); |
||||
assert_slices_equal(buf.ops[4].data.slice, test_slice_4); |
||||
GPR_ASSERT(buf.ops[5].type == GRPC_NO_OP); |
||||
|
||||
/* initialize the second buffer */ |
||||
grpc_sopb_init(&buf2); |
||||
/* add a no-op, and then the original buffer */ |
||||
grpc_sopb_add_no_op(&buf2); |
||||
grpc_sopb_append(&buf2, buf.ops, buf.nops); |
||||
/* should be one element bigger than the original */ |
||||
GPR_ASSERT(buf2.nops == buf.nops + 1); |
||||
GPR_ASSERT(buf2.ops[0].type == GRPC_NO_OP); |
||||
/* and the tail should be the same */ |
||||
for (i = 0; i < buf.nops; i++) { |
||||
GPR_ASSERT(buf2.ops[i + 1].type == buf.ops[i].type); |
||||
} |
||||
|
||||
/* destroy the buffers */ |
||||
grpc_sopb_destroy(&buf); |
||||
grpc_sopb_destroy(&buf2); |
||||
|
||||
gpr_slice_unref(test_slice_1); |
||||
gpr_slice_unref(test_slice_2); |
||||
gpr_slice_unref(test_slice_3); |
||||
gpr_slice_unref(test_slice_4); |
||||
|
||||
return 0; |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue