diff options
Diffstat (limited to 'src/core/channel')
-rw-r--r-- | src/core/channel/call_op_string.c | 51 | ||||
-rw-r--r-- | src/core/channel/census_filter.c | 24 | ||||
-rw-r--r-- | src/core/channel/channel_stack.c | 57 | ||||
-rw-r--r-- | src/core/channel/channel_stack.h | 31 | ||||
-rw-r--r-- | src/core/channel/client_channel.c | 99 | ||||
-rw-r--r-- | src/core/channel/connected_channel.c | 77 | ||||
-rw-r--r-- | src/core/channel/http_client_filter.c | 77 | ||||
-rw-r--r-- | src/core/channel/http_server_filter.c | 240 | ||||
-rw-r--r-- | src/core/channel/metadata_buffer.c | 149 | ||||
-rw-r--r-- | src/core/channel/metadata_buffer.h | 70 |
10 files changed, 255 insertions, 620 deletions
diff --git a/src/core/channel/call_op_string.c b/src/core/channel/call_op_string.c index 08f2e95deb..5f7e1be268 100644 --- a/src/core/channel/call_op_string.c +++ b/src/core/channel/call_op_string.c @@ -43,12 +43,27 @@ static void put_metadata(gpr_strvec *b, grpc_mdelem *md) { gpr_strvec_add(b, gpr_strdup(" key=")); - gpr_strvec_add(b, gpr_hexdump((char *)GPR_SLICE_START_PTR(md->key->slice), - GPR_SLICE_LENGTH(md->key->slice), GPR_HEXDUMP_PLAINTEXT)); + gpr_strvec_add( + b, gpr_hexdump((char *)GPR_SLICE_START_PTR(md->key->slice), + GPR_SLICE_LENGTH(md->key->slice), GPR_HEXDUMP_PLAINTEXT)); gpr_strvec_add(b, gpr_strdup(" value=")); gpr_strvec_add(b, gpr_hexdump((char *)GPR_SLICE_START_PTR(md->value->slice), - GPR_SLICE_LENGTH(md->value->slice), GPR_HEXDUMP_PLAINTEXT)); + GPR_SLICE_LENGTH(md->value->slice), + GPR_HEXDUMP_PLAINTEXT)); +} + +static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) { + grpc_linked_mdelem *m; + for (m = md.list.head; m != NULL; m = m->next) { + put_metadata(b, m->md); + } + if (gpr_time_cmp(md.deadline, gpr_inf_future) != 0) { + char *tmp; + gpr_asprintf(&tmp, " deadline=%d.%09d", md.deadline.tv_sec, + md.deadline.tv_nsec); + gpr_strvec_add(b, tmp); + } } char *grpc_call_op_string(grpc_call_op *op) { @@ -69,16 +84,7 @@ char *grpc_call_op_string(grpc_call_op *op) { switch (op->type) { case GRPC_SEND_METADATA: gpr_strvec_add(&b, gpr_strdup("SEND_METADATA")); - put_metadata(&b, op->data.metadata); - break; - case GRPC_SEND_DEADLINE: - gpr_asprintf(&tmp, "SEND_DEADLINE %d.%09d", op->data.deadline.tv_sec, - op->data.deadline.tv_nsec); - gpr_strvec_add(&b, tmp); - break; - case GRPC_SEND_START: - gpr_asprintf(&tmp, "SEND_START pollset=%p", op->data.start.pollset); - gpr_strvec_add(&b, tmp); + put_metadata_list(&b, op->data.metadata); break; case GRPC_SEND_MESSAGE: gpr_strvec_add(&b, gpr_strdup("SEND_MESSAGE")); @@ -94,15 +100,7 @@ char *grpc_call_op_string(grpc_call_op *op) { break; case GRPC_RECV_METADATA: gpr_strvec_add(&b, gpr_strdup("RECV_METADATA")); - put_metadata(&b, op->data.metadata); - break; - case GRPC_RECV_DEADLINE: - gpr_asprintf(&tmp, "RECV_DEADLINE %d.%09d", op->data.deadline.tv_sec, - op->data.deadline.tv_nsec); - gpr_strvec_add(&b, tmp); - break; - case GRPC_RECV_END_OF_INITIAL_METADATA: - gpr_strvec_add(&b, gpr_strdup("RECV_END_OF_INITIAL_METADATA")); + put_metadata_list(&b, op->data.metadata); break; case GRPC_RECV_MESSAGE: gpr_strvec_add(&b, gpr_strdup("RECV_MESSAGE")); @@ -113,12 +111,21 @@ char *grpc_call_op_string(grpc_call_op *op) { case GRPC_RECV_FINISH: gpr_strvec_add(&b, gpr_strdup("RECV_FINISH")); break; + case GRPC_RECV_SYNTHETIC_STATUS: + gpr_asprintf(&tmp, "RECV_SYNTHETIC_STATUS status=%d message='%s'", + op->data.synthetic_status.status, + op->data.synthetic_status.message); + gpr_strvec_add(&b, tmp); + break; case GRPC_CANCEL_OP: gpr_strvec_add(&b, gpr_strdup("CANCEL_OP")); break; } gpr_asprintf(&tmp, " flags=0x%08x", op->flags); gpr_strvec_add(&b, tmp); + if (op->bind_pollset) { + gpr_strvec_add(&b, gpr_strdup("bind_pollset")); + } out = gpr_strvec_flatten(&b, NULL); gpr_strvec_destroy(&b); diff --git a/src/core/channel/census_filter.c b/src/core/channel/census_filter.c index ba7b7ba59c..9c0c20af22 100644 --- a/src/core/channel/census_filter.c +++ b/src/core/channel/census_filter.c @@ -62,11 +62,13 @@ static void init_rpc_stats(census_rpc_stats* stats) { static void extract_and_annotate_method_tag(grpc_call_op* op, call_data* calld, channel_data* chand) { - if (op->data.metadata->key == chand->path_str) { - gpr_log(GPR_DEBUG, - (const char*)GPR_SLICE_START_PTR(op->data.metadata->value->slice)); - census_add_method_tag(calld->op_id, (const char*)GPR_SLICE_START_PTR( - op->data.metadata->value->slice)); + grpc_linked_mdelem* m; + for (m = op->data.metadata.list.head; m != NULL; m = m->next) { + if (m->md->key == chand->path_str) { + gpr_log(GPR_DEBUG, "%s", (const char*)GPR_SLICE_START_PTR(m->md->value->slice)); + census_add_method_tag( + calld->op_id, (const char*)GPR_SLICE_START_PTR(m->md->value->slice)); + } } } @@ -178,11 +180,11 @@ static void destroy_channel_elem(grpc_channel_element* elem) { } const grpc_channel_filter grpc_client_census_filter = { - client_call_op, channel_op, sizeof(call_data), - client_init_call_elem, client_destroy_call_elem, sizeof(channel_data), - init_channel_elem, destroy_channel_elem, "census-client"}; + client_call_op, channel_op, sizeof(call_data), client_init_call_elem, + client_destroy_call_elem, sizeof(channel_data), init_channel_elem, + destroy_channel_elem, "census-client"}; const grpc_channel_filter grpc_server_census_filter = { - server_call_op, channel_op, sizeof(call_data), - server_init_call_elem, server_destroy_call_elem, sizeof(channel_data), - init_channel_elem, destroy_channel_elem, "census-server"}; + server_call_op, channel_op, sizeof(call_data), server_init_call_elem, + server_destroy_call_elem, sizeof(channel_data), init_channel_elem, + destroy_channel_elem, "census-server"}; diff --git a/src/core/channel/channel_stack.c b/src/core/channel/channel_stack.c index 21df9771ce..3a3a3a75b7 100644 --- a/src/core/channel/channel_stack.c +++ b/src/core/channel/channel_stack.c @@ -77,9 +77,9 @@ size_t grpc_channel_stack_size(const grpc_channel_filter **filters, return size; } -#define CHANNEL_ELEMS_FROM_STACK(stk) \ - ((grpc_channel_element *)( \ - (char *)(stk) + ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_channel_stack)))) +#define CHANNEL_ELEMS_FROM_STACK(stk) \ + ((grpc_channel_element *)((char *)(stk) + ROUND_UP_TO_ALIGNMENT_SIZE( \ + sizeof(grpc_channel_stack)))) #define CALL_ELEMS_FROM_STACK(stk) \ ((grpc_call_element *)((char *)(stk) + \ @@ -183,6 +183,9 @@ void grpc_call_stack_destroy(grpc_call_stack *stack) { void grpc_call_next_op(grpc_call_element *elem, grpc_call_op *op) { grpc_call_element *next_elem = elem + op->dir; + if (op->type == GRPC_SEND_METADATA || op->type == GRPC_RECV_METADATA) { + grpc_metadata_batch_assert_ok(&op->data.metadata); + } next_elem->filter->call_op(next_elem, elem, op); } @@ -193,42 +196,17 @@ void grpc_channel_next_op(grpc_channel_element *elem, grpc_channel_op *op) { grpc_channel_stack *grpc_channel_stack_from_top_element( grpc_channel_element *elem) { - return (grpc_channel_stack *)((char *)(elem) - - ROUND_UP_TO_ALIGNMENT_SIZE( - sizeof(grpc_channel_stack))); + return (grpc_channel_stack *)((char *)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE( + sizeof(grpc_channel_stack))); } grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem) { - return (grpc_call_stack *)((char *)(elem) - ROUND_UP_TO_ALIGNMENT_SIZE( - sizeof(grpc_call_stack))); + return (grpc_call_stack *)((char *)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE( + sizeof(grpc_call_stack))); } static void do_nothing(void *user_data, grpc_op_error error) {} -void grpc_call_element_recv_metadata(grpc_call_element *cur_elem, - grpc_mdelem *mdelem) { - grpc_call_op metadata_op; - metadata_op.type = GRPC_RECV_METADATA; - metadata_op.dir = GRPC_CALL_UP; - metadata_op.done_cb = do_nothing; - metadata_op.user_data = NULL; - metadata_op.flags = 0; - metadata_op.data.metadata = mdelem; - grpc_call_next_op(cur_elem, &metadata_op); -} - -void grpc_call_element_send_metadata(grpc_call_element *cur_elem, - grpc_mdelem *mdelem) { - grpc_call_op metadata_op; - metadata_op.type = GRPC_SEND_METADATA; - metadata_op.dir = GRPC_CALL_DOWN; - metadata_op.done_cb = do_nothing; - metadata_op.user_data = NULL; - metadata_op.flags = 0; - metadata_op.data.metadata = mdelem; - grpc_call_next_op(cur_elem, &metadata_op); -} - void grpc_call_element_send_cancel(grpc_call_element *cur_elem) { grpc_call_op cancel_op; cancel_op.type = GRPC_CANCEL_OP; @@ -236,6 +214,7 @@ void grpc_call_element_send_cancel(grpc_call_element *cur_elem) { cancel_op.done_cb = do_nothing; cancel_op.user_data = NULL; cancel_op.flags = 0; + cancel_op.bind_pollset = NULL; grpc_call_next_op(cur_elem, &cancel_op); } @@ -246,5 +225,19 @@ void grpc_call_element_send_finish(grpc_call_element *cur_elem) { finish_op.done_cb = do_nothing; finish_op.user_data = NULL; finish_op.flags = 0; + finish_op.bind_pollset = NULL; grpc_call_next_op(cur_elem, &finish_op); } + +void grpc_call_element_recv_status(grpc_call_element *cur_elem, + grpc_status_code status, + const char *message) { + grpc_call_op op; + op.type = GRPC_RECV_SYNTHETIC_STATUS; + op.dir = GRPC_CALL_UP; + op.done_cb = do_nothing; + op.user_data = NULL; + op.data.synthetic_status.status = status; + op.data.synthetic_status.message = message; + grpc_call_next_op(cur_elem, &op); +} diff --git a/src/core/channel/channel_stack.h b/src/core/channel/channel_stack.h index ef1da7b33b..addc92b272 100644 --- a/src/core/channel/channel_stack.h +++ b/src/core/channel/channel_stack.h @@ -62,10 +62,6 @@ typedef struct grpc_call_element grpc_call_element; typedef enum { /* send metadata to the channels peer */ GRPC_SEND_METADATA, - /* send a deadline */ - GRPC_SEND_DEADLINE, - /* start a connection (corresponds to start_invoke/accept) */ - GRPC_SEND_START, /* send a message to the channels peer */ GRPC_SEND_MESSAGE, /* send a pre-formatted message to the channels peer */ @@ -76,16 +72,14 @@ typedef enum { GRPC_REQUEST_DATA, /* metadata was received from the channels peer */ GRPC_RECV_METADATA, - /* receive a deadline */ - GRPC_RECV_DEADLINE, - /* the end of the first batch of metadata was received */ - GRPC_RECV_END_OF_INITIAL_METADATA, /* a message was received from the channels peer */ GRPC_RECV_MESSAGE, /* half-close was received from the channels peer */ GRPC_RECV_HALF_CLOSE, /* full close was received from the channels peer */ GRPC_RECV_FINISH, + /* a status has been sythesized locally */ + GRPC_RECV_SYNTHETIC_STATUS, /* the call has been abnormally terminated */ GRPC_CANCEL_OP } grpc_call_op_type; @@ -109,14 +103,16 @@ typedef struct { /* Argument data, matching up with grpc_call_op_type names */ union { - struct { - grpc_pollset *pollset; - } start; grpc_byte_buffer *message; - grpc_mdelem *metadata; - gpr_timespec deadline; + grpc_metadata_batch metadata; + struct { + grpc_status_code status; + const char *message; + } synthetic_status; } data; + grpc_pollset *bind_pollset; + /* Must be called when processing of this call-op is complete. Signature chosen to match transport flow control callbacks */ void (*done_cb)(void *user_data, grpc_op_error error); @@ -291,16 +287,15 @@ grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem); void grpc_call_log_op(char *file, int line, gpr_log_severity severity, grpc_call_element *elem, grpc_call_op *op); -void grpc_call_element_send_metadata(grpc_call_element *cur_elem, - grpc_mdelem *elem); -void grpc_call_element_recv_metadata(grpc_call_element *cur_elem, - grpc_mdelem *elem); void grpc_call_element_send_cancel(grpc_call_element *cur_elem); void grpc_call_element_send_finish(grpc_call_element *cur_elem); +void grpc_call_element_recv_status(grpc_call_element *cur_elem, + grpc_status_code status, + const char *message); extern int grpc_trace_channel; #define GRPC_CALL_LOG_OP(sev, elem, op) \ if (grpc_trace_channel) grpc_call_log_op(sev, elem, op) -#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_STACK_H */ +#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_STACK_H */ diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c index 9791f98be8..bc481e59ca 100644 --- a/src/core/channel/client_channel.c +++ b/src/core/channel/client_channel.c @@ -38,7 +38,6 @@ #include "src/core/channel/channel_args.h" #include "src/core/channel/child_channel.h" #include "src/core/channel/connected_channel.h" -#include "src/core/channel/metadata_buffer.h" #include "src/core/iomgr/iomgr.h" #include "src/core/support/string.h" #include <grpc/support/alloc.h> @@ -70,9 +69,6 @@ typedef struct { int transport_setup_initiated; grpc_channel_args *args; - - /* metadata cache */ - grpc_mdelem *cancel_status; } channel_data; typedef enum { @@ -86,20 +82,16 @@ struct call_data { /* owning element */ grpc_call_element *elem; + gpr_uint8 got_first_send; + call_state state; - grpc_metadata_buffer pending_metadata; gpr_timespec deadline; union { struct { /* our child call stack */ grpc_child_call *child_call; } active; - struct { - void (*on_complete)(void *user_data, grpc_op_error error); - void *on_complete_user_data; - gpr_uint32 start_flags; - grpc_pollset *pollset; - } waiting; + grpc_call_op waiting_op; } s; }; @@ -127,20 +119,6 @@ static void complete_activate(grpc_call_element *elem, grpc_call_op *op) { GPR_ASSERT(calld->state == CALL_ACTIVE); - /* sending buffered metadata down the stack before the start call */ - grpc_metadata_buffer_flush(&calld->pending_metadata, child_elem); - - if (gpr_time_cmp(calld->deadline, gpr_inf_future) != 0) { - grpc_call_op dop; - dop.type = GRPC_SEND_DEADLINE; - dop.dir = GRPC_CALL_DOWN; - dop.flags = 0; - dop.data.deadline = calld->deadline; - dop.done_cb = do_nothing; - dop.user_data = NULL; - child_elem->filter->call_op(child_elem, elem, &dop); - } - /* continue the start call down the stack, this nees to happen after metadata are flushed*/ child_elem->filter->call_op(child_elem, elem, op); @@ -152,6 +130,7 @@ static void start_rpc(grpc_call_element *elem, grpc_call_op *op) { gpr_mu_lock(&chand->mu); if (calld->state == CALL_CANCELLED) { gpr_mu_unlock(&chand->mu); + grpc_metadata_batch_destroy(&op->data.metadata); op->done_cb(op->user_data, GRPC_OP_ERROR); return; } @@ -184,10 +163,7 @@ static void start_rpc(grpc_call_element *elem, grpc_call_op *op) { gpr_realloc(chand->waiting_children, chand->waiting_child_capacity * sizeof(call_data *)); } - calld->s.waiting.on_complete = op->done_cb; - calld->s.waiting.on_complete_user_data = op->user_data; - calld->s.waiting.start_flags = op->flags; - calld->s.waiting.pollset = op->data.start.pollset; + calld->s.waiting_op = *op; chand->waiting_children[chand->waiting_child_count++] = calld; gpr_mu_unlock(&chand->mu); @@ -212,15 +188,8 @@ static void remove_waiting_child(channel_data *chand, call_data *calld) { static void send_up_cancelled_ops(grpc_call_element *elem) { grpc_call_op finish_op; - channel_data *chand = elem->channel_data; /* send up a synthesized status */ - finish_op.type = GRPC_RECV_METADATA; - finish_op.dir = GRPC_CALL_UP; - finish_op.flags = 0; - finish_op.data.metadata = grpc_mdelem_ref(chand->cancel_status); - finish_op.done_cb = do_nothing; - finish_op.user_data = NULL; - grpc_call_next_op(elem, &finish_op); + grpc_call_element_recv_status(elem, GRPC_STATUS_CANCELLED, "Cancelled"); /* send up a finish */ finish_op.type = GRPC_RECV_FINISH; finish_op.dir = GRPC_CALL_UP; @@ -243,12 +212,12 @@ static void cancel_rpc(grpc_call_element *elem, grpc_call_op *op) { child_elem->filter->call_op(child_elem, elem, op); return; /* early out */ case CALL_WAITING: + grpc_metadata_batch_destroy(&calld->s.waiting_op.data.metadata); remove_waiting_child(chand, calld); calld->state = CALL_CANCELLED; gpr_mu_unlock(&chand->mu); send_up_cancelled_ops(elem); - calld->s.waiting.on_complete(calld->s.waiting.on_complete_user_data, - GRPC_OP_ERROR); + calld->s.waiting_op.done_cb(calld->s.waiting_op.user_data, GRPC_OP_ERROR); return; /* early out */ case CALL_CREATED: calld->state = CALL_CANCELLED; @@ -271,15 +240,13 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, switch (op->type) { case GRPC_SEND_METADATA: - grpc_metadata_buffer_queue(&calld->pending_metadata, op); - break; - case GRPC_SEND_DEADLINE: - calld->deadline = op->data.deadline; - op->done_cb(op->user_data, GRPC_OP_OK); - break; - case GRPC_SEND_START: - /* filter out the start event to find which child to send on */ - start_rpc(elem, op); + if (!calld->got_first_send) { + /* filter out the start event to find which child to send on */ + calld->got_first_send = 1; + start_rpc(elem, op); + } else { + grpc_call_next_op(elem, op); + } break; case GRPC_CANCEL_OP: cancel_rpc(elem, op); @@ -382,12 +349,6 @@ static void channel_op(grpc_channel_element *elem, } } -static void error_bad_on_complete(void *arg, grpc_op_error error) { - gpr_log(GPR_ERROR, - "Waiting finished but not started? Bad on_complete callback"); - abort(); -} - /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, const void *server_transport_data) { @@ -398,23 +359,22 @@ static void init_call_elem(grpc_call_element *elem, calld->elem = elem; calld->state = CALL_CREATED; calld->deadline = gpr_inf_future; - calld->s.waiting.on_complete = error_bad_on_complete; - calld->s.waiting.on_complete_user_data = NULL; - grpc_metadata_buffer_init(&calld->pending_metadata); + calld->got_first_send = 0; } /* Destructor for call_data */ static void destroy_call_elem(grpc_call_element *elem) { call_data *calld = elem->call_data; - /* if the metadata buffer is not flushed, destroy it here. */ - grpc_metadata_buffer_destroy(&calld->pending_metadata, GRPC_OP_OK); /* if the call got activated, we need to destroy the child stack also, and remove it from the in-flight requests tracked by the child_entry we picked */ if (calld->state == CALL_ACTIVE) { grpc_child_call_destroy(calld->s.active.child_call); } + if (calld->state == CALL_WAITING) { + grpc_metadata_batch_destroy(&calld->s.waiting_op.data.metadata); + } } /* Constructor for channel_data */ @@ -423,7 +383,6 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_mdctx *metadata_context, int is_first, int is_last) { channel_data *chand = elem->channel_data; - char temp[GPR_LTOA_MIN_BUFSIZE]; GPR_ASSERT(!is_first); GPR_ASSERT(is_last); @@ -437,10 +396,6 @@ static void init_channel_elem(grpc_channel_element *elem, chand->transport_setup = NULL; chand->transport_setup_initiated = 0; chand->args = grpc_channel_args_copy(args); - - gpr_ltoa(GRPC_STATUS_CANCELLED, temp); - chand->cancel_status = - grpc_mdelem_from_strings(metadata_context, "grpc-status", temp); } /* Destructor for channel_data */ @@ -455,7 +410,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } grpc_channel_args_destroy(chand->args); - grpc_mdelem_unref(chand->cancel_status); gpr_mu_destroy(&chand->mu); GPR_ASSERT(chand->waiting_child_count == 0); @@ -463,9 +417,10 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_client_channel_filter = { - call_op, channel_op, sizeof(call_data), - init_call_elem, destroy_call_elem, sizeof(channel_data), - init_channel_elem, destroy_channel_elem, "client-channel", }; + call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, + sizeof(channel_data), init_channel_elem, destroy_channel_elem, + "client-channel", +}; grpc_transport_setup_result grpc_client_channel_transport_setup_complete( grpc_channel_stack *channel_stack, grpc_transport *transport, @@ -520,13 +475,7 @@ grpc_transport_setup_result grpc_client_channel_transport_setup_complete( call_ops = gpr_malloc(sizeof(grpc_call_op) * waiting_child_count); for (i = 0; i < waiting_child_count; i++) { - call_ops[i].type = GRPC_SEND_START; - call_ops[i].dir = GRPC_CALL_DOWN; - call_ops[i].flags = waiting_children[i]->s.waiting.start_flags; - call_ops[i].done_cb = waiting_children[i]->s.waiting.on_complete; - call_ops[i].user_data = - waiting_children[i]->s.waiting.on_complete_user_data; - call_ops[i].data.start.pollset = waiting_children[i]->s.waiting.pollset; + call_ops[i] = waiting_children[i]->s.waiting_op; if (!prepare_activate(waiting_children[i]->elem, chand->active_child)) { waiting_children[i] = NULL; call_ops[i].done_cb(call_ops[i].user_data, GRPC_OP_ERROR); diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c index 62611e08f3..711274bfe1 100644 --- a/src/core/channel/connected_channel.c +++ b/src/core/channel/connected_channel.c @@ -60,7 +60,6 @@ typedef struct connected_channel_call_data { gpr_uint32 max_message_length; gpr_uint32 incoming_message_length; gpr_uint8 reading_message; - gpr_uint8 got_metadata_boundary; gpr_uint8 got_read_close; gpr_slice_buffer incoming_message; gpr_uint32 outgoing_buffer_length_estimate; @@ -120,27 +119,20 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); GRPC_CALL_LOG_OP(GPR_INFO, elem, op); + if (op->bind_pollset) { + grpc_transport_add_to_pollset(chand->transport, op->bind_pollset); + } + switch (op->type) { case GRPC_SEND_METADATA: grpc_sopb_add_metadata(&calld->outgoing_sopb, op->data.metadata); - grpc_sopb_add_flow_ctl_cb(&calld->outgoing_sopb, op->done_cb, - op->user_data); - break; - case GRPC_SEND_DEADLINE: - grpc_sopb_add_deadline(&calld->outgoing_sopb, op->data.deadline); - grpc_sopb_add_flow_ctl_cb(&calld->outgoing_sopb, op->done_cb, - op->user_data); - break; - case GRPC_SEND_START: - grpc_transport_add_to_pollset(chand->transport, op->data.start.pollset); - grpc_sopb_add_metadata_boundary(&calld->outgoing_sopb); end_bufferable_op(op, chand, calld, 0); break; case GRPC_SEND_MESSAGE: grpc_sopb_add_begin_message(&calld->outgoing_sopb, grpc_byte_buffer_length(op->data.message), op->flags); - /* fall-through */ + /* fall-through */ case GRPC_SEND_PREFORMATTED_MESSAGE: copy_byte_buffer_to_stream_ops(op->data.message, &calld->outgoing_sopb); calld->outgoing_buffer_length_estimate += @@ -200,7 +192,6 @@ static void init_call_elem(grpc_call_element *elem, grpc_sopb_init(&calld->outgoing_sopb); calld->reading_message = 0; - calld->got_metadata_boundary = 0; calld->got_read_close = 0; calld->outgoing_buffer_length_estimate = 0; calld->max_message_length = chand->max_message_length; @@ -259,9 +250,9 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_connected_channel_filter = { - call_op, channel_op, sizeof(call_data), - init_call_elem, destroy_call_elem, sizeof(channel_data), - init_channel_elem, destroy_channel_elem, "connected", }; + call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, + sizeof(channel_data), init_channel_elem, destroy_channel_elem, "connected", +}; static gpr_slice alloc_recv_buffer(void *user_data, grpc_transport *transport, grpc_stream *stream, size_t size_hint) { @@ -307,8 +298,8 @@ static void finish_message(channel_data *chand, call_data *calld) { call_op.type = GRPC_RECV_MESSAGE; call_op.done_cb = do_nothing; /* TODO(ctiller): this could be a lot faster if coded directly */ - call_op.data.message = grpc_byte_buffer_create( - calld->incoming_message.slices, calld->incoming_message.count); + call_op.data.message = grpc_byte_buffer_create(calld->incoming_message.slices, + calld->incoming_message.count); gpr_slice_buffer_reset_and_unref(&calld->incoming_message); /* disable window updates until we get a request more from above */ @@ -320,6 +311,19 @@ static void finish_message(channel_data *chand, call_data *calld) { grpc_call_next_op(elem, &call_op); } +static void got_metadata(grpc_call_element *elem, + grpc_metadata_batch metadata) { + grpc_call_op op; + op.type = GRPC_RECV_METADATA; + op.dir = GRPC_CALL_UP; + op.flags = 0; + op.data.metadata = metadata; + op.done_cb = do_nothing; + op.user_data = NULL; + + grpc_call_next_op(elem, &op); +} + /* Handle incoming stream ops from the transport, translating them into call_ops to pass up the call stack */ static void recv_batch(void *user_data, grpc_transport *transport, @@ -339,40 +343,12 @@ static void recv_batch(void *user_data, grpc_transport *transport, stream_op = ops + i; switch (stream_op->type) { case GRPC_OP_FLOW_CTL_CB: - gpr_log(GPR_ERROR, - "should not receive flow control ops from transport"); - abort(); + stream_op->data.flow_ctl_cb.cb(stream_op->data.flow_ctl_cb.arg, 1); break; case GRPC_NO_OP: break; case GRPC_OP_METADATA: - call_op.type = GRPC_RECV_METADATA; - call_op.dir = GRPC_CALL_UP; - call_op.flags = 0; - call_op.data.metadata = stream_op->data.metadata; - call_op.done_cb = do_nothing; - call_op.user_data = NULL; - grpc_call_next_op(elem, &call_op); - break; - case GRPC_OP_DEADLINE: - call_op.type = GRPC_RECV_DEADLINE; - call_op.dir = GRPC_CALL_UP; - call_op.flags = 0; - call_op.data.deadline = stream_op->data.deadline; - call_op.done_cb = do_nothing; - call_op.user_data = NULL; - grpc_call_next_op(elem, &call_op); - break; - case GRPC_OP_METADATA_BOUNDARY: - if (!calld->got_metadata_boundary) { - calld->got_metadata_boundary = 1; - call_op.type = GRPC_RECV_END_OF_INITIAL_METADATA; - call_op.dir = GRPC_CALL_UP; - call_op.flags = 0; - call_op.done_cb = do_nothing; - call_op.user_data = NULL; - grpc_call_next_op(elem, &call_op); - } + got_metadata(elem, stream_op->data.metadata); break; case GRPC_OP_BEGIN_MESSAGE: /* can't begin a message when we're still reading a message */ @@ -495,7 +471,8 @@ static void transport_closed(void *user_data, grpc_transport *transport) { const grpc_transport_callbacks connected_channel_transport_callbacks = { alloc_recv_buffer, accept_stream, recv_batch, - transport_goaway, transport_closed, }; + transport_goaway, transport_closed, +}; grpc_transport_setup_result grpc_connected_channel_bind_transport( grpc_channel_stack *channel_stack, grpc_transport *transport) { diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c index 3ccc39b717..56e12342d7 100644 --- a/src/core/channel/http_client_filter.c +++ b/src/core/channel/http_client_filter.c @@ -35,7 +35,10 @@ #include <grpc/support/log.h> typedef struct call_data { - int sent_headers; + grpc_linked_mdelem method; + grpc_linked_mdelem scheme; + grpc_linked_mdelem te_trailers; + grpc_linked_mdelem content_type; } call_data; typedef struct channel_data { @@ -49,6 +52,18 @@ typedef struct channel_data { /* used to silence 'variable not used' warnings */ static void ignore_unused(void *ignored) {} +static grpc_mdelem *client_filter(void *user_data, grpc_mdelem *md) { + grpc_call_element *elem = user_data; + channel_data *channeld = elem->channel_data; + if (md == channeld->status) { + return NULL; + } else if (md->key == channeld->status->key) { + grpc_call_element_send_cancel(elem); + return NULL; + } + return md; +} + /* Called either: - in response to an API call (or similar) from above, to send something - a network event (or similar) from below, to receive something @@ -61,42 +76,23 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, channel_data *channeld = elem->channel_data; GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - ignore_unused(calld); - switch (op->type) { case GRPC_SEND_METADATA: - if (!calld->sent_headers) { - /* Send : prefixed headers, which have to be before any application - * layer headers. */ - calld->sent_headers = 1; - grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->method)); - grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->scheme)); - } - grpc_call_next_op(elem, op); - break; - case GRPC_SEND_START: - if (!calld->sent_headers) { - /* Send : prefixed headers, if we haven't already */ - calld->sent_headers = 1; - grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->method)); - grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->scheme)); - } - /* Send non : prefixed headers */ - grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->te_trailers)); - grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->content_type)); + /* Send : prefixed headers, which have to be before any application + * layer headers. */ + grpc_metadata_batch_add_head(&op->data.metadata, &calld->method, + grpc_mdelem_ref(channeld->method)); + grpc_metadata_batch_add_head(&op->data.metadata, &calld->scheme, + grpc_mdelem_ref(channeld->scheme)); + grpc_metadata_batch_add_tail(&op->data.metadata, &calld->te_trailers, + grpc_mdelem_ref(channeld->te_trailers)); + grpc_metadata_batch_add_tail(&op->data.metadata, &calld->content_type, + grpc_mdelem_ref(channeld->content_type)); grpc_call_next_op(elem, op); break; case GRPC_RECV_METADATA: - if (op->data.metadata == channeld->status) { - grpc_mdelem_unref(op->data.metadata); - op->done_cb(op->user_data, GRPC_OP_OK); - } else if (op->data.metadata->key == channeld->status->key) { - grpc_mdelem_unref(op->data.metadata); - op->done_cb(op->user_data, GRPC_OP_OK); - grpc_call_element_send_cancel(elem); - } else { - grpc_call_next_op(elem, op); - } + grpc_metadata_batch_filter(&op->data.metadata, client_filter, elem); + grpc_call_next_op(elem, op); break; default: /* pass control up or down the stack depending on op->dir */ @@ -124,16 +120,7 @@ static void channel_op(grpc_channel_element *elem, /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, - const void *server_transport_data) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - channel_data *channeld = elem->channel_data; - - ignore_unused(channeld); - - /* initialize members */ - calld->sent_headers = 0; -} + const void *server_transport_data) {} /* Destructor for call_data */ static void destroy_call_elem(grpc_call_element *elem) { @@ -194,6 +181,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_http_client_filter = { - call_op, channel_op, sizeof(call_data), - init_call_elem, destroy_call_elem, sizeof(channel_data), - init_channel_elem, destroy_channel_elem, "http-client"}; + call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, + sizeof(channel_data), init_channel_elem, destroy_channel_elem, + "http-client"}; diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c index 9da8b333ca..0bfe2f2e30 100644 --- a/src/core/channel/http_server_filter.c +++ b/src/core/channel/http_server_filter.c @@ -38,8 +38,6 @@ #include <grpc/support/alloc.h> #include <grpc/support/log.h> -typedef enum { NOT_RECEIVED, POST, GET } known_method_type; - typedef struct { grpc_mdelem *path; grpc_mdelem *content_type; @@ -47,16 +45,17 @@ typedef struct { } gettable; typedef struct call_data { - known_method_type seen_method; + gpr_uint8 got_initial_metadata; + gpr_uint8 seen_path; + gpr_uint8 seen_post; gpr_uint8 sent_status; gpr_uint8 seen_scheme; gpr_uint8 seen_te_trailers; - grpc_mdelem *path; + grpc_linked_mdelem status; } call_data; typedef struct channel_data { grpc_mdelem *te_trailers; - grpc_mdelem *method_get; grpc_mdelem *method_post; grpc_mdelem *http_scheme; grpc_mdelem *https_scheme; @@ -78,38 +77,70 @@ typedef struct channel_data { /* used to silence 'variable not used' warnings */ static void ignore_unused(void *ignored) {} -/* Handle 'GET': not technically grpc, so probably a web browser hitting - us */ -static void payload_done(void *elem, grpc_op_error error) { - if (error == GRPC_OP_OK) { - grpc_call_element_send_finish(elem); - } -} - -static void handle_get(grpc_call_element *elem) { +static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) { + grpc_call_element *elem = user_data; channel_data *channeld = elem->channel_data; call_data *calld = elem->call_data; - grpc_call_op op; - size_t i; - for (i = 0; i < channeld->gettable_count; i++) { - if (channeld->gettables[i].path == calld->path) { - grpc_call_element_send_metadata(elem, - grpc_mdelem_ref(channeld->status_ok)); - grpc_call_element_send_metadata( - elem, grpc_mdelem_ref(channeld->gettables[i].content_type)); - op.type = GRPC_SEND_PREFORMATTED_MESSAGE; - op.dir = GRPC_CALL_DOWN; - op.flags = 0; - op.data.message = channeld->gettables[i].content; - op.done_cb = payload_done; - op.user_data = elem; - grpc_call_next_op(elem, &op); + /* Check if it is one of the headers we care about. */ + if (md == channeld->te_trailers || md == channeld->method_post || + md == channeld->http_scheme || md == channeld->https_scheme || + md == channeld->grpc_scheme || md == channeld->content_type) { + /* swallow it */ + if (md == channeld->method_post) { + calld->seen_post = 1; + } else if (md->key == channeld->http_scheme->key) { + calld->seen_scheme = 1; + } else if (md == channeld->te_trailers) { + calld->seen_te_trailers = 1; } + /* TODO(klempner): Track that we've seen all the headers we should + require */ + return NULL; + } else if (md->key == channeld->content_type->key) { + if (strncmp(grpc_mdstr_as_c_string(md->value), "application/grpc+", 17) == + 0) { + /* Although the C implementation doesn't (currently) generate them, + any custom +-suffix is explicitly valid. */ + /* TODO(klempner): We should consider preallocating common values such + as +proto or +json, or at least stashing them if we see them. */ + /* TODO(klempner): Should we be surfacing this to application code? */ + } else { + /* TODO(klempner): We're currently allowing this, but we shouldn't + see it without a proxy so log for now. */ + gpr_log(GPR_INFO, "Unexpected content-type %s", + channeld->content_type->key); + } + return NULL; + } else if (md->key == channeld->te_trailers->key || + md->key == channeld->method_post->key || + md->key == channeld->http_scheme->key || + md->key == channeld->content_type->key) { + gpr_log(GPR_ERROR, "Invalid %s: header: '%s'", + grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)); + /* swallow it and error everything out. */ + /* TODO(klempner): We ought to generate more descriptive error messages + on the wire here. */ + grpc_call_element_send_cancel(elem); + return NULL; + } else if (md->key == channeld->path_key) { + if (calld->seen_path) { + gpr_log(GPR_ERROR, "Received :path twice"); + return NULL; + } + calld->seen_path = 1; + return md; + } else if (md->key == channeld->host_key) { + /* translate host to :authority since :authority may be + omitted */ + grpc_mdelem *authority = grpc_mdelem_from_metadata_strings( + channeld->mdctx, grpc_mdstr_ref(channeld->authority_key), + grpc_mdstr_ref(md->value)); + grpc_mdelem_unref(md); + return authority; + } else { + return md; } - grpc_call_element_send_metadata(elem, - grpc_mdelem_ref(channeld->status_not_found)); - grpc_call_element_send_finish(elem); } /* Called either: @@ -126,115 +157,44 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, switch (op->type) { case GRPC_RECV_METADATA: - /* Check if it is one of the headers we care about. */ - if (op->data.metadata == channeld->te_trailers || - op->data.metadata == channeld->method_get || - op->data.metadata == channeld->method_post || - op->data.metadata == channeld->http_scheme || - op->data.metadata == channeld->https_scheme || - op->data.metadata == channeld->grpc_scheme || - op->data.metadata == channeld->content_type) { - /* swallow it */ - if (op->data.metadata == channeld->method_get) { - calld->seen_method = GET; - } else if (op->data.metadata == channeld->method_post) { - calld->seen_method = POST; - } else if (op->data.metadata->key == channeld->http_scheme->key) { - calld->seen_scheme = 1; - } else if (op->data.metadata == channeld->te_trailers) { - calld->seen_te_trailers = 1; - } - /* TODO(klempner): Track that we've seen all the headers we should - require */ - grpc_mdelem_unref(op->data.metadata); - op->done_cb(op->user_data, GRPC_OP_OK); - } else if (op->data.metadata->key == channeld->content_type->key) { - if (strncmp(grpc_mdstr_as_c_string(op->data.metadata->value), - "application/grpc+", 17) == 0) { - /* Although the C implementation doesn't (currently) generate them, - any - custom +-suffix is explicitly valid. */ - /* TODO(klempner): We should consider preallocating common values such - as +proto or +json, or at least stashing them if we see them. */ - /* TODO(klempner): Should we be surfacing this to application code? */ + grpc_metadata_batch_filter(&op->data.metadata, server_filter, elem); + if (!calld->got_initial_metadata) { + calld->got_initial_metadata = 1; + /* Have we seen the required http2 transport headers? + (:method, :scheme, content-type, with :path and :authority covered + at the channel level right now) */ + if (calld->seen_post && calld->seen_scheme && calld->seen_te_trailers && + calld->seen_path) { + grpc_call_next_op(elem, op); } else { - /* TODO(klempner): We're currently allowing this, but we shouldn't - see it without a proxy so log for now. */ - gpr_log(GPR_INFO, "Unexpected content-type %s", - channeld->content_type->key); - } - grpc_mdelem_unref(op->data.metadata); - op->done_cb(op->user_data, GRPC_OP_OK); - } else if (op->data.metadata->key == channeld->te_trailers->key || - op->data.metadata->key == channeld->method_post->key || - op->data.metadata->key == channeld->http_scheme->key || - op->data.metadata->key == channeld->content_type->key) { - gpr_log(GPR_ERROR, "Invalid %s: header: '%s'", - grpc_mdstr_as_c_string(op->data.metadata->key), - grpc_mdstr_as_c_string(op->data.metadata->value)); - /* swallow it and error everything out. */ - /* TODO(klempner): We ought to generate more descriptive error messages - on the wire here. */ - grpc_mdelem_unref(op->data.metadata); - op->done_cb(op->user_data, GRPC_OP_OK); - grpc_call_element_send_cancel(elem); - } else if (op->data.metadata->key == channeld->path_key) { - if (calld->path != NULL) { - gpr_log(GPR_ERROR, "Received :path twice"); - grpc_mdelem_unref(calld->path); + if (!calld->seen_path) { + gpr_log(GPR_ERROR, "Missing :path header"); + } + if (!calld->seen_post) { + gpr_log(GPR_ERROR, "Missing :method header"); + } + if (!calld->seen_scheme) { + gpr_log(GPR_ERROR, "Missing :scheme header"); + } + if (!calld->seen_te_trailers) { + gpr_log(GPR_ERROR, "Missing te trailers header"); + } + /* Error this call out */ + grpc_metadata_batch_destroy(&op->data.metadata); + op->done_cb(op->user_data, GRPC_OP_OK); + grpc_call_element_send_cancel(elem); } - calld->path = op->data.metadata; - op->done_cb(op->user_data, GRPC_OP_OK); - } else if (op->data.metadata->key == channeld->host_key) { - /* translate host to :authority since :authority may be - omitted */ - grpc_mdelem *authority = grpc_mdelem_from_metadata_strings( - channeld->mdctx, grpc_mdstr_ref(channeld->authority_key), - grpc_mdstr_ref(op->data.metadata->value)); - grpc_mdelem_unref(op->data.metadata); - op->data.metadata = authority; - /* pass the event up */ - grpc_call_next_op(elem, op); } else { - /* pass the event up */ grpc_call_next_op(elem, op); } break; - case GRPC_RECV_END_OF_INITIAL_METADATA: - /* Have we seen the required http2 transport headers? - (:method, :scheme, content-type, with :path and :authority covered - at the channel level right now) */ - if (calld->seen_method == POST && calld->seen_scheme && - calld->seen_te_trailers && calld->path) { - grpc_call_element_recv_metadata(elem, calld->path); - calld->path = NULL; - grpc_call_next_op(elem, op); - } else if (calld->seen_method == GET) { - handle_get(elem); - } else { - if (calld->seen_method == NOT_RECEIVED) { - gpr_log(GPR_ERROR, "Missing :method header"); - } - if (!calld->seen_scheme) { - gpr_log(GPR_ERROR, "Missing :scheme header"); - } - if (!calld->seen_te_trailers) { - gpr_log(GPR_ERROR, "Missing te trailers header"); - } - /* Error this call out */ - op->done_cb(op->user_data, GRPC_OP_OK); - grpc_call_element_send_cancel(elem); - } - break; - case GRPC_SEND_START: case GRPC_SEND_METADATA: /* If we haven't sent status 200 yet, we need to so so because it needs to come before any non : prefixed metadata. */ if (!calld->sent_status) { calld->sent_status = 1; - /* status is reffed by grpc_call_element_send_metadata */ - grpc_call_element_send_metadata(elem, - grpc_mdelem_ref(channeld->status_ok)); + grpc_metadata_batch_add_head(&op->data.metadata, &calld->status, + grpc_mdelem_ref(channeld->status_ok)); } grpc_call_next_op(elem, op); break; @@ -272,25 +232,11 @@ static void init_call_elem(grpc_call_element *elem, ignore_unused(channeld); /* initialize members */ - calld->path = NULL; - calld->sent_status = 0; - calld->seen_scheme = 0; - calld->seen_method = NOT_RECEIVED; - calld->seen_te_trailers = 0; + memset(calld, 0, sizeof(*calld)); } /* Destructor for call_data */ -static void destroy_call_elem(grpc_call_element *elem) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - channel_data *channeld = elem->channel_data; - - ignore_unused(channeld); - - if (calld->path) { - grpc_mdelem_unref(calld->path); - } -} +static void destroy_call_elem(grpc_call_element *elem) {} /* Constructor for channel_data */ static void init_channel_elem(grpc_channel_element *elem, @@ -314,7 +260,6 @@ static void init_channel_elem(grpc_channel_element *elem, channeld->status_not_found = grpc_mdelem_from_strings(mdctx, ":status", "404"); channeld->method_post = grpc_mdelem_from_strings(mdctx, ":method", "POST"); - channeld->method_get = grpc_mdelem_from_strings(mdctx, ":method", "GET"); channeld->http_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "http"); channeld->https_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "https"); channeld->grpc_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "grpc"); @@ -369,7 +314,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) { grpc_mdelem_unref(channeld->status_ok); grpc_mdelem_unref(channeld->status_not_found); grpc_mdelem_unref(channeld->method_post); - grpc_mdelem_unref(channeld->method_get); grpc_mdelem_unref(channeld->http_scheme); grpc_mdelem_unref(channeld->https_scheme); grpc_mdelem_unref(channeld->grpc_scheme); diff --git a/src/core/channel/metadata_buffer.c b/src/core/channel/metadata_buffer.c deleted file mode 100644 index eac852e4a4..0000000000 --- a/src/core/channel/metadata_buffer.c +++ /dev/null @@ -1,149 +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/channel/metadata_buffer.h" -#include <grpc/support/alloc.h> -#include <grpc/support/log.h> -#include <grpc/support/useful.h> - -#include <string.h> - -#define INITIAL_ELEM_CAP 8 - -/* One queued call; we track offsets to string data in a shared buffer to - reduce allocations. See grpc_metadata_buffer_impl for the memory use - strategy */ -typedef struct { - grpc_mdelem *md; - void (*cb)(void *user_data, grpc_op_error error); - void *user_data; - gpr_uint32 flags; -} qelem; - -/* Memory layout: - - grpc_metadata_buffer_impl - followed by an array of qelem */ -struct grpc_metadata_buffer_impl { - /* number of elements in q */ - size_t elems; - /* capacity of q */ - size_t elem_cap; -}; - -#define ELEMS(buffer) ((qelem *)((buffer) + 1)) - -void grpc_metadata_buffer_init(grpc_metadata_buffer *buffer) { - /* start buffer as NULL, indicating no elements */ - *buffer = NULL; -} - -void grpc_metadata_buffer_destroy(grpc_metadata_buffer *buffer, - grpc_op_error error) { - size_t i; - qelem *qe; - if (*buffer) { - for (i = 0; i < (*buffer)->elems; i++) { - qe = &ELEMS(*buffer)[i]; - grpc_mdelem_unref(qe->md); - qe->cb(qe->user_data, error); - } - gpr_free(*buffer); - } -} - -void grpc_metadata_buffer_queue(grpc_metadata_buffer *buffer, - grpc_call_op *op) { - grpc_metadata_buffer_impl *impl = *buffer; - qelem *qe; - size_t bytes; - - GPR_ASSERT(op->type == GRPC_SEND_METADATA || op->type == GRPC_RECV_METADATA); - - if (!impl) { - /* this is the first element: allocate enough space to hold the - header object and the initial element capacity of qelems */ - bytes = - sizeof(grpc_metadata_buffer_impl) + INITIAL_ELEM_CAP * sizeof(qelem); - impl = gpr_malloc(bytes); - /* initialize the header object */ - impl->elems = 0; - impl->elem_cap = INITIAL_ELEM_CAP; - } else if (impl->elems == impl->elem_cap) { - /* more qelems than what we can deal with: grow by doubling size */ - impl->elem_cap *= 2; - bytes = sizeof(grpc_metadata_buffer_impl) + impl->elem_cap * sizeof(qelem); - impl = gpr_realloc(impl, bytes); - } - - /* append an element to the queue */ - qe = &ELEMS(impl)[impl->elems]; - impl->elems++; - - qe->md = op->data.metadata; - qe->cb = op->done_cb; - qe->user_data = op->user_data; - qe->flags = op->flags; - - /* header object may have changed location: store it back */ - *buffer = impl; -} - -void grpc_metadata_buffer_flush(grpc_metadata_buffer *buffer, - grpc_call_element *elem) { - grpc_metadata_buffer_impl *impl = *buffer; - grpc_call_op op; - qelem *qe; - size_t i; - - if (!impl) { - /* nothing to send */ - return; - } - - /* construct call_op's, and push them down the stack */ - op.type = GRPC_SEND_METADATA; - op.dir = GRPC_CALL_DOWN; - for (i = 0; i < impl->elems; i++) { - qe = &ELEMS(impl)[i]; - op.done_cb = qe->cb; - op.user_data = qe->user_data; - op.flags = qe->flags; - op.data.metadata = qe->md; - grpc_call_next_op(elem, &op); - } - - /* free data structures and reset to NULL: we can only flush once */ - gpr_free(impl); - *buffer = NULL; -} diff --git a/src/core/channel/metadata_buffer.h b/src/core/channel/metadata_buffer.h deleted file mode 100644 index b7cc5170d1..0000000000 --- a/src/core/channel/metadata_buffer.h +++ /dev/null @@ -1,70 +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_CHANNEL_METADATA_BUFFER_H -#define GRPC_INTERNAL_CORE_CHANNEL_METADATA_BUFFER_H - -#include "src/core/channel/channel_stack.h" - -/* Utility code to buffer GRPC_SEND_METADATA calls and pass them down the stack - all at once at some otherwise-determined time. Useful for implementing - filters that want to queue metadata until a START event chooses some - underlying filter stack to send an rpc on. */ - -/* Clients should declare a member of grpc_metadata_buffer. This may at some - point become a typedef for a struct, but for now a pointer suffices */ -typedef struct grpc_metadata_buffer_impl grpc_metadata_buffer_impl; -typedef grpc_metadata_buffer_impl *grpc_metadata_buffer; - -/* Initializes the metadata buffer. Allocates no memory. */ -void grpc_metadata_buffer_init(grpc_metadata_buffer *buffer); -/* Destroy the metadata buffer. */ -void grpc_metadata_buffer_destroy(grpc_metadata_buffer *buffer, - grpc_op_error error); -/* Append a call to the end of a metadata buffer: may allocate memory */ -void grpc_metadata_buffer_queue(grpc_metadata_buffer *buffer, grpc_call_op *op); -/* Flush all queued operations from the metadata buffer to the element below - self */ -void grpc_metadata_buffer_flush(grpc_metadata_buffer *buffer, - grpc_call_element *self); -/* Count the number of queued elements in the buffer. */ -size_t grpc_metadata_buffer_count(const grpc_metadata_buffer *buffer); -/* Extract elements as a grpc_metadata*, for presentation to applications. - The returned buffer must be freed with - grpc_metadata_buffer_cleanup_elements. - Clears the metadata buffer (this is a one-shot operation) */ -grpc_metadata *grpc_metadata_buffer_extract_elements( - grpc_metadata_buffer *buffer); -void grpc_metadata_buffer_cleanup_elements(void *elements, grpc_op_error error); - -#endif /* GRPC_INTERNAL_CORE_CHANNEL_METADATA_BUFFER_H */ |