Пример #1
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);
  }
}
Пример #2
0
void grpc_chttp2_publish_reads(
    grpc_chttp2_transport_global *transport_global,
    grpc_chttp2_transport_parsing *transport_parsing) {
    grpc_chttp2_stream_global *stream_global;
    grpc_chttp2_stream_parsing *stream_parsing;

    /* transport_parsing->last_incoming_stream_id is used as
       last-grpc_chttp2_stream-id when
       sending GOAWAY frame.
       https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-6.8
       says that last-grpc_chttp2_stream-id is peer-initiated grpc_chttp2_stream
       ID.  So,
       since we don't have server pushed streams, client should send
       GOAWAY last-grpc_chttp2_stream-id=0 in this case. */
    if (!transport_parsing->is_client) {
        transport_global->last_incoming_stream_id =
            transport_parsing->incoming_stream_id;
    }

    /* copy parsing qbuf to global qbuf */
    gpr_slice_buffer_move_into(&transport_parsing->qbuf, &transport_global->qbuf);

    /* update global settings */
    if (transport_parsing->settings_updated) {
        memcpy(transport_global->settings[GRPC_PEER_SETTINGS],
               transport_parsing->settings, sizeof(transport_parsing->settings));
        transport_parsing->settings_updated = 0;
    }

    /* update settings based on ack if received */
    if (transport_parsing->settings_ack_received) {
        memcpy(transport_global->settings[GRPC_ACKED_SETTINGS],
               transport_global->settings[GRPC_SENT_SETTINGS],
               GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
        transport_parsing->settings_ack_received = 0;
    }

    /* move goaway to the global state if we received one (it will be
       published later */
    if (transport_parsing->goaway_received) {
        grpc_chttp2_add_incoming_goaway(transport_global,
                                        transport_parsing->goaway_error,
                                        transport_parsing->goaway_text);
        transport_parsing->goaway_text = gpr_empty_slice();
        transport_parsing->goaway_received = 0;
    }

    /* propagate flow control tokens to global state */
    if (transport_parsing->outgoing_window_update) {
        GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
            "parsed", transport_global, outgoing_window,
            transport_parsing->outgoing_window_update);
        GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
            "parsed", transport_parsing, outgoing_window_update,
            -(gpr_int64)transport_parsing->outgoing_window_update);
        transport_global->outgoing_window +=
            transport_parsing->outgoing_window_update;
        transport_parsing->outgoing_window_update = 0;
    }

    if (transport_parsing->incoming_window_delta) {
        GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
            "parsed", transport_global, incoming_window,
            -(gpr_int64)transport_parsing->incoming_window_delta);
        GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
            "parsed", transport_parsing, incoming_window_delta,
            -(gpr_int64)transport_parsing->incoming_window_delta);
        transport_global->incoming_window -=
            transport_parsing->incoming_window_delta;
        transport_parsing->incoming_window_delta = 0;
    }

    /* for each stream that saw an update, fixup global state */
    while (grpc_chttp2_list_pop_parsing_seen_stream(
                transport_global, transport_parsing, &stream_global, &stream_parsing)) {
        /* update incoming flow control window */
        if (stream_parsing->incoming_window_delta) {
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
                "parsed", transport_parsing, stream_global, incoming_window,
                -(gpr_int64)stream_parsing->incoming_window_delta);
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
                "parsed", transport_parsing, stream_parsing, incoming_window_delta,
                -(gpr_int64)stream_parsing->incoming_window_delta);
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
                "parsed", transport_parsing, stream_global, max_recv_bytes,
                -(gpr_int64)stream_parsing->incoming_window_delta);
            stream_global->incoming_window -= stream_parsing->incoming_window_delta;
            GPR_ASSERT(stream_global->max_recv_bytes >=
                       stream_parsing->incoming_window_delta);
            stream_global->max_recv_bytes -=
                stream_parsing->incoming_window_delta;
            stream_parsing->incoming_window_delta = 0;
            grpc_chttp2_list_add_writable_window_update_stream(transport_global,
                    stream_global);
        }

        /* update outgoing flow control window */
        if (stream_parsing->outgoing_window_update) {
            int was_zero = stream_global->outgoing_window <= 0;
            int is_zero;
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("parsed", transport_parsing,
                                             stream_global, outgoing_window,
                                             stream_parsing->outgoing_window_update);
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
                "parsed", transport_parsing, stream_parsing, outgoing_window_update,
                -(gpr_int64)stream_parsing->outgoing_window_update);
            stream_global->outgoing_window += stream_parsing->outgoing_window_update;
            stream_parsing->outgoing_window_update = 0;
            is_zero = stream_global->outgoing_window <= 0;
            if (was_zero && !is_zero) {
                grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
            }
        }

        /* updating closed status */
        if (stream_parsing->received_close) {
            stream_global->read_closed = 1;
            grpc_chttp2_list_add_read_write_state_changed(transport_global,
                    stream_global);
        }
        if (stream_parsing->saw_rst_stream) {
            stream_global->cancelled = 1;
            stream_global->cancelled_status = grpc_chttp2_http2_error_to_grpc_status(
                                                  stream_parsing->rst_stream_reason);
            if (stream_parsing->rst_stream_reason == GRPC_CHTTP2_NO_ERROR) {
                stream_global->published_cancelled = 1;
            }
            grpc_chttp2_list_add_read_write_state_changed(transport_global,
                    stream_global);
        }

        /* publish incoming stream ops */
        if (stream_parsing->data_parser.incoming_sopb.nops > 0) {
            grpc_incoming_metadata_buffer_move_to_referencing_sopb(
                &stream_parsing->incoming_metadata, &stream_global->incoming_metadata,
                &stream_parsing->data_parser.incoming_sopb);
            grpc_sopb_move_to(&stream_parsing->data_parser.incoming_sopb,
                              &stream_global->incoming_sopb);
            grpc_chttp2_list_add_read_write_state_changed(transport_global,
                    stream_global);
        }
    }
}