grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, const void *server_transport_data, grpc_mdelem **add_initial_metadata, size_t add_initial_metadata_count, gpr_timespec send_deadline) { size_t i; grpc_transport_op initial_op; grpc_transport_op *initial_op_ptr = NULL; grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel); grpc_call *call = gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size); memset(call, 0, sizeof(grpc_call)); gpr_mu_init(&call->mu); call->channel = channel; call->cq = cq; call->is_client = server_transport_data == NULL; for (i = 0; i < GRPC_IOREQ_OP_COUNT; i++) { call->request_set[i] = REQSET_EMPTY; } if (call->is_client) { call->request_set[GRPC_IOREQ_SEND_TRAILING_METADATA] = REQSET_DONE; call->request_set[GRPC_IOREQ_SEND_STATUS] = REQSET_DONE; } GPR_ASSERT(add_initial_metadata_count < MAX_SEND_INITIAL_METADATA_COUNT); for (i = 0; i < add_initial_metadata_count; i++) { call->send_initial_metadata[i].md = add_initial_metadata[i]; } call->send_initial_metadata_count = add_initial_metadata_count; call->send_deadline = send_deadline; grpc_channel_internal_ref(channel); call->metadata_context = grpc_channel_get_metadata_context(channel); grpc_sopb_init(&call->send_ops); grpc_sopb_init(&call->recv_ops); gpr_slice_buffer_init(&call->incoming_message); /* dropped in destroy */ gpr_ref_init(&call->internal_refcount, 1); /* server hack: start reads immediately so we can get initial metadata. TODO(ctiller): figure out a cleaner solution */ if (!call->is_client) { memset(&initial_op, 0, sizeof(initial_op)); initial_op.recv_ops = &call->recv_ops; initial_op.recv_state = &call->recv_state; initial_op.on_done_recv = call_on_done_recv; initial_op.recv_user_data = call; initial_op.context = call->context; call->receiving = 1; GRPC_CALL_INTERNAL_REF(call, "receiving"); initial_op_ptr = &initial_op; } grpc_call_stack_init(channel_stack, server_transport_data, initial_op_ptr, CALL_STACK_FROM_CALL(call)); if (gpr_time_cmp(send_deadline, gpr_inf_future) != 0) { set_deadline_alarm(call, send_deadline); } return call; }
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); }
static int init_stream(grpc_transport *gt, grpc_stream *gs, const void *server_data, grpc_transport_stream_op *initial_op) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; memset(s, 0, sizeof(*s)); grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.incoming_metadata); grpc_chttp2_incoming_metadata_buffer_init(&s->global.incoming_metadata); grpc_sopb_init(&s->writing.sopb); grpc_sopb_init(&s->global.incoming_sopb); grpc_chttp2_data_parser_init(&s->parsing.data_parser); REF_TRANSPORT(t, "stream"); lock(t); grpc_chttp2_register_stream(t, s); if (server_data) { GPR_ASSERT(t->parsing_active); s->global.id = (gpr_uint32)(gpr_uintptr)server_data; s->global.outgoing_window = t->global.settings[GRPC_PEER_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; s->global.max_recv_bytes = s->parsing.incoming_window = s->global.incoming_window = t->global.settings[GRPC_SENT_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; *t->accepting_stream = s; grpc_chttp2_stream_map_add(&t->parsing_stream_map, s->global.id, s); s->global.in_stream_map = 1; } if (initial_op) perform_stream_op_locked(&t->global, &s->global, initial_op); unlock(t); return 0; }
/** Assembles a new grpc_stream_op_buffer with the compressed slices, modifying * the associated GRPC_OP_BEGIN_MESSAGE accordingly (new compressed length, * flags indicating compression is in effect) and replaces \a send_ops with it. * */ static void finish_compressed_sopb(grpc_stream_op_buffer *send_ops, grpc_call_element *elem) { size_t i; call_data *calld = elem->call_data; int new_slices_added = 0; /* GPR_FALSE */ grpc_metadata_batch metadata; grpc_stream_op_buffer new_send_ops; grpc_sopb_init(&new_send_ops); for (i = 0; i < send_ops->nops; i++) { grpc_stream_op *sop = &send_ops->ops[i]; switch (sop->type) { case GRPC_OP_BEGIN_MESSAGE: GPR_ASSERT(calld->slices.length <= GPR_UINT32_MAX); grpc_sopb_add_begin_message( &new_send_ops, (gpr_uint32)calld->slices.length, sop->data.begin_message.flags | GRPC_WRITE_INTERNAL_COMPRESS); break; case GRPC_OP_SLICE: /* Once we reach the slices section of the original buffer, simply add * all the new (compressed) slices. We obviously want to do this only * once, hence the "new_slices_added" guard. */ if (!new_slices_added) { size_t j; for (j = 0; j < calld->slices.count; ++j) { grpc_sopb_add_slice(&new_send_ops, gpr_slice_ref(calld->slices.slices[j])); } new_slices_added = 1; /* GPR_TRUE */ } break; case GRPC_OP_METADATA: /* move the metadata to the new buffer. */ grpc_metadata_batch_move(&metadata, &sop->data.metadata); grpc_sopb_add_metadata(&new_send_ops, metadata); break; case GRPC_NO_OP: break; } } grpc_sopb_swap(send_ops, &new_send_ops); grpc_sopb_destroy(&new_send_ops); }
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); }
/* 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, 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_hexdump((char *)GPR_SLICE_START_PTR(expect), GPR_SLICE_LENGTH(expect), GPR_HEXDUMP_PLAINTEXT); char *got_str = gpr_hexdump((char *)GPR_SLICE_START_PTR(merged), GPR_SLICE_LENGTH(merged), GPR_HEXDUMP_PLAINTEXT); 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); }
grpc_chttp2_parse_error grpc_chttp2_data_parser_init( grpc_chttp2_data_parser *parser) { parser->state = GRPC_CHTTP2_DATA_FH_0; grpc_sopb_init(&parser->incoming_sopb); return GRPC_CHTTP2_PARSE_OK; }
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; }