Exemple #1
0
static void unlock_check_channel_callbacks(grpc_chttp2_transport *t) {
  if (t->channel_callback.executing) {
    return;
  }
  if (t->global.goaway_state != GRPC_CHTTP2_ERROR_STATE_NONE) {
    if (t->global.goaway_state == GRPC_CHTTP2_ERROR_STATE_SEEN &&
        t->global.error_state != GRPC_CHTTP2_ERROR_STATE_NOTIFIED) {
      notify_goaways_args *a = gpr_malloc(sizeof(*a));
      a->t = t;
      a->error = t->global.goaway_error;
      a->text = t->global.goaway_text;
      t->global.goaway_state = GRPC_CHTTP2_ERROR_STATE_NOTIFIED;
      t->channel_callback.executing = 1;
      grpc_iomgr_closure_init(&a->closure, notify_goaways, a);
      REF_TRANSPORT(t, "notify_goaways");
      grpc_chttp2_schedule_closure(&t->global, &a->closure, 1);
      return;
    } else if (t->global.goaway_state != GRPC_CHTTP2_ERROR_STATE_NOTIFIED) {
      return;
    }
  }
  if (t->global.error_state == GRPC_CHTTP2_ERROR_STATE_SEEN) {
    t->global.error_state = GRPC_CHTTP2_ERROR_STATE_NOTIFIED;
    t->channel_callback.executing = 1;
    REF_TRANSPORT(t, "notify_closed");
    grpc_chttp2_schedule_closure(&t->global, &t->channel_callback.notify_closed,
                                 1);
  }
}
Exemple #2
0
static void perform_op_locked(grpc_chttp2_transport_global *transport_global,
                              grpc_chttp2_stream_global *stream_global,
                              grpc_transport_op *op) {
  if (op->cancel_with_status != GRPC_STATUS_OK) {
    cancel_from_api(transport_global, stream_global, op->cancel_with_status);
  }

  if (op->send_ops) {
    GPR_ASSERT(stream_global->outgoing_sopb == NULL);
    stream_global->send_done_closure = op->on_done_send;
    if (!stream_global->cancelled) {
      stream_global->outgoing_sopb = op->send_ops;
      if (op->is_last_send &&
          stream_global->write_state == GRPC_WRITE_STATE_OPEN) {
        stream_global->write_state = GRPC_WRITE_STATE_QUEUED_CLOSE;
      }
      if (stream_global->id == 0) {
        GRPC_CHTTP2_IF_TRACING(gpr_log(
            GPR_DEBUG,
            "HTTP:%s: New grpc_chttp2_stream %p waiting for concurrency",
            transport_global->is_client ? "CLI" : "SVR", stream_global));
        grpc_chttp2_list_add_waiting_for_concurrency(transport_global,
                                                     stream_global);
        maybe_start_some_streams(transport_global);
      } else if (stream_global->outgoing_window > 0) {
        grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
      }
    } else {
      grpc_sopb_reset(op->send_ops);
      grpc_chttp2_schedule_closure(transport_global,
                                   stream_global->send_done_closure, 0);
    }
  }

  if (op->recv_ops) {
    GPR_ASSERT(stream_global->publish_sopb == NULL);
    GPR_ASSERT(stream_global->published_state != GRPC_STREAM_CLOSED);
    stream_global->recv_done_closure = op->on_done_recv;
    stream_global->publish_sopb = op->recv_ops;
    stream_global->publish_sopb->nops = 0;
    stream_global->publish_state = op->recv_state;
    grpc_chttp2_incoming_metadata_live_op_buffer_end(
        &stream_global->outstanding_metadata);
    grpc_chttp2_list_add_read_write_state_changed(transport_global,
                                                  stream_global);
    grpc_chttp2_list_add_writable_window_update_stream(transport_global,
                                                       stream_global);
  }

  if (op->bind_pollset) {
    add_to_pollset_locked(TRANSPORT_FROM_GLOBAL(transport_global),
                          op->bind_pollset);
  }

  if (op->on_consumed) {
    grpc_chttp2_schedule_closure(transport_global, op->on_consumed, 1);
  }
}
Exemple #3
0
void grpc_chttp2_cleanup_writing(
    grpc_chttp2_transport_global *transport_global,
    grpc_chttp2_transport_writing *transport_writing) {
    grpc_chttp2_stream_writing *stream_writing;
    grpc_chttp2_stream_global *stream_global;

    while (grpc_chttp2_list_pop_written_stream(
                transport_global, transport_writing, &stream_global, &stream_writing)) {
        GPR_ASSERT(stream_global->writing_now != 0);
        if (stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) {
            stream_global->write_state = GRPC_WRITE_STATE_SENT_CLOSE;
            if (!transport_global->is_client) {
                stream_global->read_closed = 1;
            }
        }
        if (stream_global->writing_now & GRPC_CHTTP2_WRITING_DATA) {
            if (stream_global->outgoing_sopb != NULL &&
                    stream_global->outgoing_sopb->nops == 0) {
                GPR_ASSERT(stream_global->write_state != GRPC_WRITE_STATE_QUEUED_CLOSE);
                stream_global->outgoing_sopb = NULL;
                grpc_chttp2_schedule_closure(transport_global,
                                             stream_global->send_done_closure, 1);
            }
        }
        stream_global->writing_now = 0;
        grpc_chttp2_list_add_read_write_state_changed(transport_global,
                stream_global);
    }
    transport_writing->outbuf.count = 0;
    transport_writing->outbuf.length = 0;
}
Exemple #4
0
static void perform_transport_op(grpc_transport *gt, grpc_transport_op *op) {
  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
  int close_transport = 0;

  lock(t);

  if (op->on_consumed) {
    grpc_chttp2_schedule_closure(&t->global, op->on_consumed, 1);
  }

  if (op->on_connectivity_state_change) {
    grpc_connectivity_state_notify_on_state_change(
        &t->channel_callback.state_tracker, op->connectivity_state,
        op->on_connectivity_state_change);
  }

  if (op->send_goaway) {
    t->global.sent_goaway = 1;
    grpc_chttp2_goaway_append(
        t->global.last_incoming_stream_id,
        grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
        gpr_slice_ref(*op->goaway_message), &t->global.qbuf);
    close_transport = !grpc_chttp2_has_streams(t);
  }

  if (op->set_accept_stream != NULL) {
    t->channel_callback.accept_stream = op->set_accept_stream;
    t->channel_callback.accept_stream_user_data =
        op->set_accept_stream_user_data;
  }

  if (op->bind_pollset) {
    add_to_pollset_locked(t, op->bind_pollset);
  }

  if (op->bind_pollset_set) {
    add_to_pollset_set_locked(t, op->bind_pollset_set);
  }

  if (op->send_ping) {
    send_ping_locked(t, op->send_ping);
  }

  if (op->disconnect) {
    close_transport_locked(t);
  }

  unlock(t);

  if (close_transport) {
    lock(t);
    close_transport_locked(t);
    unlock(t);
  }
}
Exemple #5
0
static void unlock(grpc_chttp2_transport *t) {
  grpc_iomgr_closure *run_closures;

  unlock_check_read_write_state(t);
  if (!t->writing_active && !t->closed &&
      grpc_chttp2_unlocking_check_writes(&t->global, &t->writing)) {
    t->writing_active = 1;
    REF_TRANSPORT(t, "writing");
    grpc_chttp2_schedule_closure(&t->global, &t->writing_action, 1);
  }

  run_closures = t->global.pending_closures_head;
  t->global.pending_closures_head = NULL;
  t->global.pending_closures_tail = NULL;

  gpr_mu_unlock(&t->mu);

  while (run_closures) {
    grpc_iomgr_closure *next = run_closures->next;
    run_closures->cb(run_closures->cb_arg, run_closures->success);
    run_closures = next;
  }
}
Exemple #6
0
static void unlock(grpc_chttp2_transport *t) {
  grpc_iomgr_closure *run_closures;

  unlock_check_read_write_state(t);
  if (!t->writing_active && t->global.error_state == GRPC_CHTTP2_ERROR_STATE_NONE &&
      grpc_chttp2_unlocking_check_writes(&t->global, &t->writing)) {
    t->writing_active = 1;
    REF_TRANSPORT(t, "writing");
    grpc_chttp2_schedule_closure(&t->global, &t->writing_action, 1);
  }
  /* unlock_check_parser(t); */
  unlock_check_channel_callbacks(t);

  run_closures = t->global.pending_closures;
  t->global.pending_closures = NULL;

  gpr_mu_unlock(&t->mu);

  while (run_closures) {
    grpc_iomgr_closure *next = run_closures->next;
    run_closures->cb(run_closures->cb_arg, run_closures->success);
    run_closures = next;
  }
}
Exemple #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");
  }
}
Exemple #8
0
static void unlock_check_read_write_state(grpc_chttp2_transport *t) {
  grpc_chttp2_transport_global *transport_global = &t->global;
  grpc_chttp2_stream_global *stream_global;
  grpc_stream_state state;

  if (!t->parsing_active) {
    /* if a stream is in the stream map, and gets cancelled, we need to ensure
       we are not parsing before continuing the cancellation to keep things in
       a sane state */
    while (grpc_chttp2_list_pop_closed_waiting_for_parsing(transport_global,
                                                           &stream_global)) {
      GPR_ASSERT(stream_global->in_stream_map);
      GPR_ASSERT(stream_global->write_state != GRPC_WRITE_STATE_OPEN);
      GPR_ASSERT(stream_global->read_closed);
      remove_stream(t, stream_global->id);
      grpc_chttp2_list_add_read_write_state_changed(transport_global,
                                                    stream_global);
    }
  }

  while (grpc_chttp2_list_pop_read_write_state_changed(transport_global,
                                                       &stream_global)) {
    if (stream_global->cancelled) {
      stream_global->write_state = GRPC_WRITE_STATE_SENT_CLOSE;
      stream_global->read_closed = 1;
      if (!stream_global->published_cancelled) {
        char buffer[GPR_LTOA_MIN_BUFSIZE];
        gpr_ltoa(stream_global->cancelled_status, buffer);
        grpc_chttp2_incoming_metadata_buffer_add(&stream_global->incoming_metadata,
          grpc_mdelem_from_strings(t->metadata_context, "grpc-status", buffer));
        grpc_chttp2_incoming_metadata_buffer_place_metadata_batch_into(
          &stream_global->incoming_metadata,
          &stream_global->incoming_sopb);
        stream_global->published_cancelled = 1;
      }
    }
    if (stream_global->write_state == GRPC_WRITE_STATE_SENT_CLOSE &&
        stream_global->read_closed && stream_global->in_stream_map) {
      if (t->parsing_active) {
        grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global,
                                                        stream_global);
      } else {
        remove_stream(t, stream_global->id);
      }
    }
    if (!stream_global->publish_sopb) {
      continue;
    }
    /* FIXME(ctiller): we include in_stream_map in our computation of
       whether the stream is write-closed. This is completely bogus,
       but has the effect of delaying stream-closed until the stream
       is indeed evicted from the stream map, making it safe to delete.
       To fix this will require having an edge after stream-closed
       indicating that the stream is closed AND safe to delete. */
    state = compute_state(
        stream_global->write_state == GRPC_WRITE_STATE_SENT_CLOSE &&
            !stream_global->in_stream_map,
        stream_global->read_closed);
    if (stream_global->incoming_sopb.nops == 0 &&
        state == stream_global->published_state) {
      continue;
    }
    grpc_chttp2_incoming_metadata_buffer_postprocess_sopb_and_begin_live_op(
        &stream_global->incoming_metadata, &stream_global->incoming_sopb,
        &stream_global->outstanding_metadata);
    grpc_sopb_swap(stream_global->publish_sopb, &stream_global->incoming_sopb);
    stream_global->published_state = *stream_global->publish_state = state;
    grpc_chttp2_schedule_closure(transport_global,
                                 stream_global->recv_done_closure, 1);
    stream_global->recv_done_closure = NULL;
    stream_global->publish_sopb = NULL;
    stream_global->publish_state = NULL;
  }
}
Exemple #9
0
static void schedule_closure_for_connectivity(void *a,
                                              grpc_iomgr_closure *closure) {
  grpc_chttp2_schedule_closure(a, closure, 1);
}