/* test creation & destruction */ static void test_no_op(void) { grpc_chttp2_stream_map map; LOG_TEST("test_no_op"); grpc_chttp2_stream_map_init(&map, 8); grpc_chttp2_stream_map_destroy(&map); }
/* test lookup on an empty map */ static void test_empty_find(void) { grpc_chttp2_stream_map map; LOG_TEST("test_empty_find"); grpc_chttp2_stream_map_init(&map, 8); GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, 39128)); grpc_chttp2_stream_map_destroy(&map); }
/* add a bunch of keys, delete the even ones immediately, and make sure the map is consistent */ static void test_delete_evens_incremental(uint32_t n) { grpc_chttp2_stream_map map; uint32_t i; LOG_TEST("test_delete_evens_incremental"); gpr_log(GPR_INFO, "n = %d", n); grpc_chttp2_stream_map_init(&map, 8); for (i = 1; i <= n; i++) { grpc_chttp2_stream_map_add(&map, i, (void *)(uintptr_t)i); if ((i & 1) == 0) { grpc_chttp2_stream_map_delete(&map, i); } } check_delete_evens(&map, n); grpc_chttp2_stream_map_destroy(&map); }
/* test it's safe to delete twice */ static void test_double_deletion(void) { grpc_chttp2_stream_map map; LOG_TEST("test_double_deletion"); grpc_chttp2_stream_map_init(&map, 8); GPR_ASSERT(0 == grpc_chttp2_stream_map_size(&map)); grpc_chttp2_stream_map_add(&map, 1, (void *)1); GPR_ASSERT((void *)1 == grpc_chttp2_stream_map_find(&map, 1)); GPR_ASSERT(1 == grpc_chttp2_stream_map_size(&map)); GPR_ASSERT((void *)1 == grpc_chttp2_stream_map_delete(&map, 1)); GPR_ASSERT(0 == grpc_chttp2_stream_map_size(&map)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, 1)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_delete(&map, 1)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, 1)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_delete(&map, 1)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, 1)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_delete(&map, 1)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, 1)); grpc_chttp2_stream_map_destroy(&map); }
/* add a bunch of keys, delete old ones after some time, ensure the backing array does not grow */ static void test_periodic_compaction(uint32_t n) { grpc_chttp2_stream_map map; uint32_t i; uint32_t del; LOG_TEST("test_periodic_compaction"); gpr_log(GPR_INFO, "n = %d", n); grpc_chttp2_stream_map_init(&map, 16); GPR_ASSERT(map.capacity == 16); for (i = 1; i <= n; i++) { grpc_chttp2_stream_map_add(&map, i, (void *)(uintptr_t)i); if (i > 8) { del = i - 8; GPR_ASSERT((void *)(uintptr_t)del == grpc_chttp2_stream_map_delete(&map, del)); } } GPR_ASSERT(map.capacity == 16); grpc_chttp2_stream_map_destroy(&map); }
/* test add & lookup */ static void test_basic_add_find(uint32_t n) { grpc_chttp2_stream_map map; uint32_t i; size_t got; LOG_TEST("test_basic_add_find"); gpr_log(GPR_INFO, "n = %d", n); grpc_chttp2_stream_map_init(&map, 8); GPR_ASSERT(0 == grpc_chttp2_stream_map_size(&map)); for (i = 1; i <= n; i++) { grpc_chttp2_stream_map_add(&map, i, (void *)(uintptr_t)i); } GPR_ASSERT(n == grpc_chttp2_stream_map_size(&map)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, 0)); GPR_ASSERT(NULL == grpc_chttp2_stream_map_find(&map, n + 1)); for (i = 1; i <= n; i++) { got = (uintptr_t)grpc_chttp2_stream_map_find(&map, i); GPR_ASSERT(i == got); } grpc_chttp2_stream_map_destroy(&map); }
static void init_transport(grpc_chttp2_transport *t, grpc_transport_setup_callback setup, void *arg, const grpc_channel_args *channel_args, grpc_endpoint *ep, gpr_slice *slices, size_t nslices, grpc_mdctx *mdctx, int is_client) { size_t i; int j; grpc_transport_setup_result sr; GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) == GRPC_CHTTP2_CLIENT_CONNECT_STRLEN); memset(t, 0, sizeof(*t)); t->base.vtable = &vtable; t->ep = ep; /* one ref is for destroy, the other for when ep becomes NULL */ gpr_ref_init(&t->refs, 2); gpr_mu_init(&t->mu); grpc_mdctx_ref(mdctx); t->metadata_context = mdctx; t->endpoint_reading = 1; t->global.error_state = GRPC_CHTTP2_ERROR_STATE_NONE; t->global.next_stream_id = is_client ? 1 : 2; t->global.is_client = is_client; t->global.outgoing_window = DEFAULT_WINDOW; t->global.incoming_window = DEFAULT_WINDOW; t->global.connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET; t->global.ping_counter = 1; t->global.pings.next = t->global.pings.prev = &t->global.pings; t->parsing.is_client = is_client; t->parsing.str_grpc_timeout = grpc_mdstr_from_string(t->metadata_context, "grpc-timeout"); t->parsing.deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0; t->writing.is_client = is_client; gpr_slice_buffer_init(&t->global.qbuf); gpr_slice_buffer_init(&t->writing.outbuf); grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor, mdctx); grpc_iomgr_closure_init(&t->writing_action, writing_action, t); grpc_iomgr_closure_init(&t->reading_action, reading_action, t); gpr_slice_buffer_init(&t->parsing.qbuf); grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser); grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser, t->metadata_context); grpc_iomgr_closure_init(&t->channel_callback.notify_closed, notify_closed, t); if (is_client) { gpr_slice_buffer_add( &t->global.qbuf, gpr_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING)); } /* 8 is a random stab in the dark as to a good initial size: it's small enough that it shouldn't waste memory for infrequently used connections, yet large enough that the exponential growth should happen nicely when it's needed. TODO(ctiller): tune this */ grpc_chttp2_stream_map_init(&t->parsing_stream_map, 8); grpc_chttp2_stream_map_init(&t->new_stream_map, 8); /* copy in initial settings to all setting sets */ for (i = 0; i < GRPC_CHTTP2_NUM_SETTINGS; i++) { t->parsing.settings[i] = grpc_chttp2_settings_parameters[i].default_value; for (j = 0; j < GRPC_NUM_SETTING_SETS; j++) { t->global.settings[j][i] = grpc_chttp2_settings_parameters[i].default_value; } } t->global.dirtied_local_settings = 1; /* Hack: it's common for implementations to assume 65536 bytes initial send window -- this should by rights be 0 */ t->global.force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; t->global.sent_local_settings = 0; /* configure http2 the way we like it */ if (is_client) { push_setting(t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0); push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0); } push_setting(t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, DEFAULT_WINDOW); if (channel_args) { for (i = 0; i < channel_args->num_args; i++) { if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_MAX_CONCURRENT_STREAMS)) { if (is_client) { gpr_log(GPR_ERROR, "%s: is ignored on the client", GRPC_ARG_MAX_CONCURRENT_STREAMS); } else if (channel_args->args[i].type != GRPC_ARG_INTEGER) { gpr_log(GPR_ERROR, "%s: must be an integer", GRPC_ARG_MAX_CONCURRENT_STREAMS); } else { push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, channel_args->args[i].value.integer); } } else if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER)) { if (channel_args->args[i].type != GRPC_ARG_INTEGER) { gpr_log(GPR_ERROR, "%s: must be an integer", GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER); } else if ((t->global.next_stream_id & 1) != (channel_args->args[i].value.integer & 1)) { gpr_log(GPR_ERROR, "%s: low bit must be %d on %s", GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER, t->global.next_stream_id & 1, is_client ? "client" : "server"); } else { t->global.next_stream_id = channel_args->args[i].value.integer; } } } } gpr_mu_lock(&t->mu); t->channel_callback.executing = 1; REF_TRANSPORT(t, "init"); /* matches unref at end of this function */ gpr_mu_unlock(&t->mu); sr = setup(arg, &t->base, t->metadata_context); lock(t); t->channel_callback.cb = sr.callbacks; t->channel_callback.cb_user_data = sr.user_data; t->channel_callback.executing = 0; unlock(t); REF_TRANSPORT(t, "recv_data"); /* matches unref inside recv_data */ recv_data(t, slices, nslices, GRPC_ENDPOINT_CB_OK); UNREF_TRANSPORT(t, "init"); }