Ejemplo n.º 1
0
static void remove_stream(grpc_chttp2_transport *t, gpr_uint32 id) {
  size_t new_stream_count;
  grpc_chttp2_stream *s =
      grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id);
  if (!s) {
    s = grpc_chttp2_stream_map_delete(&t->new_stream_map, id);
  }
  grpc_chttp2_list_remove_writable_stream(&t->global, &s->global);
  GPR_ASSERT(s);
  s->global.in_stream_map = 0;
  if (t->parsing.incoming_stream == &s->parsing) {
    t->parsing.incoming_stream = NULL;
    grpc_chttp2_parsing_become_skip_parser(&t->parsing);
  }
  if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
    close_transport_locked(t);
  }

  new_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map) +
                     grpc_chttp2_stream_map_size(&t->new_stream_map);
  if (new_stream_count != t->global.concurrent_stream_count) {
    t->global.concurrent_stream_count = new_stream_count;
    maybe_start_some_streams(&t->global);
  }
}
Ejemplo n.º 2
0
static void destruct_transport(grpc_exec_ctx *exec_ctx,
                               grpc_chttp2_transport *t) {
  size_t i;

  gpr_mu_lock(&t->mu);

  GPR_ASSERT(t->ep == NULL);

  gpr_slice_buffer_destroy(&t->global.qbuf);

  gpr_slice_buffer_destroy(&t->writing.outbuf);
  grpc_chttp2_hpack_compressor_destroy(&t->writing.hpack_compressor);

  gpr_slice_buffer_destroy(&t->parsing.qbuf);
  gpr_slice_buffer_destroy(&t->read_buffer);
  grpc_chttp2_hpack_parser_destroy(&t->parsing.hpack_parser);
  grpc_chttp2_goaway_parser_destroy(&t->parsing.goaway_parser);

  GRPC_MDSTR_UNREF(t->parsing.str_grpc_timeout);

  for (i = 0; i < STREAM_LIST_COUNT; i++) {
    GPR_ASSERT(t->lists[i].head == NULL);
    GPR_ASSERT(t->lists[i].tail == NULL);
  }

  GPR_ASSERT(grpc_chttp2_stream_map_size(&t->parsing_stream_map) == 0);
  GPR_ASSERT(grpc_chttp2_stream_map_size(&t->new_stream_map) == 0);

  grpc_chttp2_stream_map_destroy(&t->parsing_stream_map);
  grpc_chttp2_stream_map_destroy(&t->new_stream_map);
  grpc_connectivity_state_destroy(exec_ctx, &t->channel_callback.state_tracker);

  gpr_mu_unlock(&t->mu);
  gpr_mu_destroy(&t->mu);

  /* callback remaining pings: they're not allowed to call into the transpot,
     and maybe they hold resources that need to be freed */
  while (t->global.pings.next != &t->global.pings) {
    grpc_chttp2_outstanding_ping *ping = t->global.pings.next;
    grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, 0);
    ping->next->prev = ping->prev;
    ping->prev->next = ping->next;
    gpr_free(ping);
  }

  grpc_mdctx_unref(t->metadata_context);

  gpr_free(t->peer_string);
  gpr_free(t);
}
Ejemplo n.º 3
0
/* tcp read callback */
static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, int success) {
  size_t i;
  int keep_reading = 0;
  grpc_chttp2_transport *t = tp;

  lock(t);
  i = 0;
  GPR_ASSERT(!t->parsing_active);
  if (!t->closed) {
    t->parsing_active = 1;
    /* merge stream lists */
    grpc_chttp2_stream_map_move_into(&t->new_stream_map,
                                     &t->parsing_stream_map);
    grpc_chttp2_prepare_to_read(&t->global, &t->parsing);
    gpr_mu_unlock(&t->mu);
    for (; i < t->read_buffer.count &&
               grpc_chttp2_perform_read(exec_ctx, &t->parsing,
                                        t->read_buffer.slices[i]);
         i++)
      ;
    gpr_mu_lock(&t->mu);
    if (i != t->read_buffer.count) {
      drop_connection(exec_ctx, t);
    }
    /* merge stream lists */
    grpc_chttp2_stream_map_move_into(&t->new_stream_map,
                                     &t->parsing_stream_map);
    t->global.concurrent_stream_count =
        (gpr_uint32)grpc_chttp2_stream_map_size(&t->parsing_stream_map);
    if (t->parsing.initial_window_update != 0) {
      grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
                                      update_global_window, t);
      t->parsing.initial_window_update = 0;
    }
    /* handle higher level things */
    grpc_chttp2_publish_reads(exec_ctx, &t->global, &t->parsing);
    t->parsing_active = 0;
  }
  if (!success || i != t->read_buffer.count) {
    drop_connection(exec_ctx, t);
    read_error_locked(exec_ctx, t);
  } else if (!t->closed) {
    keep_reading = 1;
    REF_TRANSPORT(t, "keep_reading");
    prevent_endpoint_shutdown(t);
  }
  gpr_slice_buffer_reset_and_unref(&t->read_buffer);
  unlock(exec_ctx, t);

  if (keep_reading) {
    grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->recv_data);
    allow_endpoint_shutdown_unlocked(exec_ctx, t);
    UNREF_TRANSPORT(exec_ctx, t, "keep_reading");
  } else {
    UNREF_TRANSPORT(exec_ctx, t, "recv_data");
  }
}
Ejemplo n.º 4
0
/* 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);
}
Ejemplo n.º 5
0
static void remove_stream(grpc_chttp2_transport *t, gpr_uint32 id) {
  size_t new_stream_count;
  grpc_chttp2_stream *s =
      grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id);
  if (!s) {
    s = grpc_chttp2_stream_map_delete(&t->new_stream_map, id);
  }
  GPR_ASSERT(s);
  s->global.in_stream_map = 0;
  if (t->parsing.incoming_stream == &s->parsing) {
    t->parsing.incoming_stream = NULL;
    grpc_chttp2_parsing_become_skip_parser(&t->parsing);
  }

  new_stream_count =
      grpc_chttp2_stream_map_size(&t->parsing_stream_map) +
      grpc_chttp2_stream_map_size(&t->new_stream_map);
  if (new_stream_count != t->global.concurrent_stream_count) {
    t->global.concurrent_stream_count = new_stream_count;
    maybe_start_some_streams(&t->global);
  }
}
Ejemplo n.º 6
0
/* 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);
}
Ejemplo n.º 7
0
/* tcp read callback */
static void recv_data(void *tp, gpr_slice *slices, size_t nslices,
                      grpc_endpoint_cb_status error) {
  grpc_chttp2_transport *t = tp;
  size_t i;
  int unref = 0;

  switch (error) {
    case GRPC_ENDPOINT_CB_SHUTDOWN:
    case GRPC_ENDPOINT_CB_EOF:
    case GRPC_ENDPOINT_CB_ERROR:
      lock(t);
      drop_connection(t);
      read_error_locked(t);
      unlock(t);
      unref = 1;
      for (i = 0; i < nslices; i++) gpr_slice_unref(slices[i]);
      break;
    case GRPC_ENDPOINT_CB_OK:
      lock(t);
      i = 0;
      GPR_ASSERT(!t->parsing_active);
      if (t->global.error_state == GRPC_CHTTP2_ERROR_STATE_NONE) {
        t->parsing_active = 1;
        /* merge stream lists */
        grpc_chttp2_stream_map_move_into(&t->new_stream_map,
                                         &t->parsing_stream_map);
        grpc_chttp2_prepare_to_read(&t->global, &t->parsing);
        gpr_mu_unlock(&t->mu);
        for (; i < nslices && grpc_chttp2_perform_read(&t->parsing, slices[i]);
             i++) {
          gpr_slice_unref(slices[i]);
        }
        gpr_mu_lock(&t->mu);
        if (i != nslices) {
          drop_connection(t);
        }
        /* merge stream lists */
        grpc_chttp2_stream_map_move_into(&t->new_stream_map,
                                         &t->parsing_stream_map);
        t->global.concurrent_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map);
        if (t->parsing.initial_window_update != 0) {
          grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
                                          update_global_window, t);
        }
        /* handle higher level things */
        grpc_chttp2_publish_reads(&t->global, &t->parsing);
        t->parsing_active = 0;
      }
      if (i == nslices) {
        grpc_chttp2_schedule_closure(&t->global, &t->reading_action, 1);
      } else {
        read_error_locked(t);
        unref = 1;
      }
      unlock(t);
      for (; i < nslices; i++) gpr_slice_unref(slices[i]);
      break;
  }
  if (unref) {
    UNREF_TRANSPORT(t, "recv_data");
  }
}
Ejemplo n.º 8
0
static grpc_error *init_header_frame_parser(grpc_exec_ctx *exec_ctx,
                                            grpc_chttp2_transport *t,
                                            int is_continuation) {
  uint8_t is_eoh =
      (t->incoming_frame_flags & GRPC_CHTTP2_DATA_FLAG_END_HEADERS) != 0;
  grpc_chttp2_stream *s;

  /* TODO(ctiller): when to increment header_frames_received? */

  if (is_eoh) {
    t->expect_continuation_stream_id = 0;
  } else {
    t->expect_continuation_stream_id = t->incoming_stream_id;
  }

  if (!is_continuation) {
    t->header_eof =
        (t->incoming_frame_flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) != 0;
  }

  t->ping_state.pings_before_data_required =
      t->ping_policy.max_pings_without_data;
  t->ping_state.last_ping_sent_time = gpr_inf_past(GPR_CLOCK_MONOTONIC);

  /* could be a new grpc_chttp2_stream or an existing grpc_chttp2_stream */
  s = grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id);
  if (s == NULL) {
    if (is_continuation) {
      GRPC_CHTTP2_IF_TRACING(
          gpr_log(GPR_ERROR,
                  "grpc_chttp2_stream disbanded before CONTINUATION received"));
      return init_skip_frame_parser(exec_ctx, t, 1);
    }
    if (t->is_client) {
      if ((t->incoming_stream_id & 1) &&
          t->incoming_stream_id < t->next_stream_id) {
        /* this is an old (probably cancelled) grpc_chttp2_stream */
      } else {
        GRPC_CHTTP2_IF_TRACING(gpr_log(
            GPR_ERROR, "ignoring new grpc_chttp2_stream creation on client"));
      }
      return init_skip_frame_parser(exec_ctx, t, 1);
    } else if (t->last_new_stream_id >= t->incoming_stream_id) {
      GRPC_CHTTP2_IF_TRACING(gpr_log(
          GPR_ERROR,
          "ignoring out of order new grpc_chttp2_stream request on server; "
          "last grpc_chttp2_stream "
          "id=%d, new grpc_chttp2_stream id=%d",
          t->last_new_stream_id, t->incoming_stream_id));
      return init_skip_frame_parser(exec_ctx, t, 1);
    } else if ((t->incoming_stream_id & 1) == 0) {
      GRPC_CHTTP2_IF_TRACING(gpr_log(
          GPR_ERROR,
          "ignoring grpc_chttp2_stream with non-client generated index %d",
          t->incoming_stream_id));
      return init_skip_frame_parser(exec_ctx, t, 1);
    } else if (grpc_chttp2_stream_map_size(&t->stream_map) >=
               t->settings[GRPC_ACKED_SETTINGS]
                          [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]) {
      return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Max stream count exceeded");
    }
    t->last_new_stream_id = t->incoming_stream_id;
    s = t->incoming_stream =
        grpc_chttp2_parsing_accept_stream(exec_ctx, t, t->incoming_stream_id);
    if (s == NULL) {
      GRPC_CHTTP2_IF_TRACING(
          gpr_log(GPR_ERROR, "grpc_chttp2_stream not accepted"));
      return init_skip_frame_parser(exec_ctx, t, 1);
    }
  } else {
    t->incoming_stream = s;
  }
  GPR_ASSERT(s != NULL);
  s->stats.incoming.framing_bytes += 9;
  if (s->read_closed) {
    GRPC_CHTTP2_IF_TRACING(gpr_log(
        GPR_ERROR, "skipping already closed grpc_chttp2_stream header"));
    t->incoming_stream = NULL;
    return init_skip_frame_parser(exec_ctx, t, 1);
  }
  t->parser = grpc_chttp2_header_parser_parse;
  t->parser_data = &t->hpack_parser;
  switch (s->header_frames_received) {
    case 0:
      if (t->is_client && t->header_eof) {
        GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_INFO, "parsing Trailers-Only"));
        if (s->trailing_metadata_available != NULL) {
          *s->trailing_metadata_available = true;
        }
        t->hpack_parser.on_header = on_trailing_header;
        s->received_trailing_metadata = true;
      } else {
        GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_INFO, "parsing initial_metadata"));
        t->hpack_parser.on_header = on_initial_header;
      }
      break;
    case 1:
      GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_INFO, "parsing trailing_metadata"));
      t->hpack_parser.on_header = on_trailing_header;
      s->received_trailing_metadata = true;
      break;
    case 2:
      gpr_log(GPR_ERROR, "too many header frames received");
      return init_skip_frame_parser(exec_ctx, t, 1);
  }
  t->hpack_parser.on_header_user_data = t;
  t->hpack_parser.is_boundary = is_eoh;
  t->hpack_parser.is_eof = (uint8_t)(is_eoh ? t->header_eof : 0);
  if (!is_continuation &&
      (t->incoming_frame_flags & GRPC_CHTTP2_FLAG_HAS_PRIORITY)) {
    grpc_chttp2_hpack_parser_set_has_priority(&t->hpack_parser);
  }
  return GRPC_ERROR_NONE;
}
Ejemplo n.º 9
0
/* tcp read callback */
static int recv_data_loop(grpc_chttp2_transport *t, int *success) {
  size_t i;
  int keep_reading = 0;

  lock(t);
  i = 0;
  GPR_ASSERT(!t->parsing_active);
  if (!t->closed) {
    t->parsing_active = 1;
    /* merge stream lists */
    grpc_chttp2_stream_map_move_into(&t->new_stream_map,
                                     &t->parsing_stream_map);
    grpc_chttp2_prepare_to_read(&t->global, &t->parsing);
    gpr_mu_unlock(&t->mu);
    for (; i < t->read_buffer.count &&
           grpc_chttp2_perform_read(&t->parsing, t->read_buffer.slices[i]);
         i++)
      ;
    gpr_mu_lock(&t->mu);
    if (i != t->read_buffer.count) {
      drop_connection(t);
    }
    /* merge stream lists */
    grpc_chttp2_stream_map_move_into(&t->new_stream_map,
                                     &t->parsing_stream_map);
    t->global.concurrent_stream_count =
        grpc_chttp2_stream_map_size(&t->parsing_stream_map);
    if (t->parsing.initial_window_update != 0) {
      grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
                                      update_global_window, t);
      t->parsing.initial_window_update = 0;
    }
    /* handle higher level things */
    grpc_chttp2_publish_reads(&t->global, &t->parsing);
    t->parsing_active = 0;
  }
  if (!*success || i != t->read_buffer.count) {
    drop_connection(t);
    read_error_locked(t);
  } else if (!t->closed) {
    keep_reading = 1;
    REF_TRANSPORT(t, "keep_reading");
    prevent_endpoint_shutdown(t);
  }
  gpr_slice_buffer_reset_and_unref(&t->read_buffer);
  unlock(t);

  if (keep_reading) {
    int ret = -1;
    switch (grpc_endpoint_read(t->ep, &t->read_buffer, &t->recv_data)) {
      case GRPC_ENDPOINT_DONE:
        *success = 1;
        ret = 1;
        break;
      case GRPC_ENDPOINT_ERROR:
        *success = 0;
        ret = 1;
        break;
      case GRPC_ENDPOINT_PENDING:
        ret = 0;
        break;
    }
    allow_endpoint_shutdown_unlocked(t);
    UNREF_TRANSPORT(t, "keep_reading");
    return ret;
  } else {
    UNREF_TRANSPORT(t, "recv_data");
    return 0;
  }

  gpr_log(GPR_ERROR, "should never reach here");
  abort();
}