Example #1
0
File: writing.c Project: bjori/grpc
static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing) {
  grpc_chttp2_stream_writing *stream_writing;

  while (
      grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) {
    if (stream_writing->sopb.nops > 0 ||
        stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) {
      grpc_chttp2_encode(stream_writing->sopb.ops, stream_writing->sopb.nops,
                         stream_writing->send_closed != GRPC_DONT_SEND_CLOSED,
                         stream_writing->id,
                         &transport_writing->hpack_compressor,
                         &transport_writing->outbuf);
      stream_writing->sopb.nops = 0;
    }
    if (stream_writing->announce_window > 0) {
      gpr_slice_buffer_add(
          &transport_writing->outbuf,
          grpc_chttp2_window_update_create(stream_writing->id,
                                           stream_writing->announce_window));
      GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
          "write", transport_writing, stream_writing, announce_window,
          -(gpr_int64)stream_writing->announce_window);
      stream_writing->announce_window = 0;
    }
    if (stream_writing->send_closed == GRPC_SEND_CLOSED_WITH_RST_STREAM) {
      gpr_slice_buffer_add(&transport_writing->outbuf,
                           grpc_chttp2_rst_stream_create(stream_writing->id,
                                                         GRPC_CHTTP2_NO_ERROR));
    }
    grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
  }
}
Example #2
0
void grpc_chttp2_prepare_to_read(
    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->next_stream_id = transport_global->next_stream_id;

    /* update the parsing view of incoming window */
    if (transport_parsing->incoming_window != transport_global->incoming_window) {
        GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
            "parse", transport_parsing, incoming_window,
            (gpr_int64)transport_global->incoming_window -
            (gpr_int64)transport_parsing->incoming_window);
        transport_parsing->incoming_window = transport_global->incoming_window;
    }
    while (grpc_chttp2_list_pop_incoming_window_updated(
                transport_global, transport_parsing, &stream_global, &stream_parsing)) {
        stream_parsing->id = stream_global->id;
        if (stream_parsing->incoming_window != stream_global->incoming_window) {
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
                "parse", transport_parsing, stream_parsing, incoming_window,
                (gpr_int64)stream_global->incoming_window -
                (gpr_int64)stream_parsing->incoming_window);
            stream_parsing->incoming_window = stream_global->incoming_window;
        }
    }
}
Example #3
0
static grpc_chttp2_parse_error update_incoming_window(
    grpc_chttp2_transport_parsing *transport_parsing,
    grpc_chttp2_stream_parsing *stream_parsing) {
    if (transport_parsing->incoming_frame_size >
            transport_parsing->incoming_window) {
        gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d",
                transport_parsing->incoming_frame_size,
                transport_parsing->incoming_window);
        return GRPC_CHTTP2_CONNECTION_ERROR;
    }

    if (transport_parsing->incoming_frame_size >
            stream_parsing->incoming_window) {
        gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d",
                transport_parsing->incoming_frame_size,
                stream_parsing->incoming_window);
        return GRPC_CHTTP2_CONNECTION_ERROR;
    }

    GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
        "data", transport_parsing, incoming_window,
        -(gpr_int64)transport_parsing->incoming_frame_size);
    GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT("data", transport_parsing,
                                        incoming_window_delta,
                                        transport_parsing->incoming_frame_size);
    GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
        "data", transport_parsing, stream_parsing, incoming_window,
        -(gpr_int64)transport_parsing->incoming_frame_size);
    GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("data", transport_parsing, stream_parsing,
                                     incoming_window_delta,
                                     transport_parsing->incoming_frame_size);

    transport_parsing->incoming_window -= transport_parsing->incoming_frame_size;
    transport_parsing->incoming_window_delta +=
        transport_parsing->incoming_frame_size;
    stream_parsing->incoming_window -= transport_parsing->incoming_frame_size;
    stream_parsing->incoming_window_delta +=
        transport_parsing->incoming_frame_size;
    grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);

    return GRPC_CHTTP2_PARSE_OK;
}
Example #4
0
/** update window from a settings change */
static void update_global_window(void *args, gpr_uint32 id, void *stream) {
  grpc_chttp2_transport *t = args;
  grpc_chttp2_stream *s = stream;
  grpc_chttp2_transport_global *transport_global = &t->global;
  grpc_chttp2_stream_global *stream_global = &s->global;

  GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("settings", transport_global, stream_global,
                                   outgoing_window,
                                   t->parsing.initial_window_update);
  stream_global->outgoing_window += t->parsing.initial_window_update;
}
Example #5
0
/** update window from a settings change */
static void update_global_window(void *args, gpr_uint32 id, void *stream) {
  grpc_chttp2_transport *t = args;
  grpc_chttp2_stream *s = stream;
  grpc_chttp2_transport_global *transport_global = &t->global;
  grpc_chttp2_stream_global *stream_global = &s->global;
  int was_zero;
  int is_zero;

  GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("settings", transport_global, stream_global,
                                   outgoing_window,
                                   t->parsing.initial_window_update);
  was_zero = stream_global->outgoing_window <= 0;
  stream_global->outgoing_window += t->parsing.initial_window_update;
  is_zero = stream_global->outgoing_window <= 0;

  if (was_zero && !is_zero) {
    grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
  }
}
Example #6
0
static void perform_stream_op_locked(
    grpc_chttp2_transport_global *transport_global,
    grpc_chttp2_stream_global *stream_global, grpc_transport_stream_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;
    if (stream_global->max_recv_bytes < op->max_recv_bytes) {
      GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("op", transport_global, stream_global,
          max_recv_bytes, op->max_recv_bytes - stream_global->max_recv_bytes);
      GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
          "op", transport_global, stream_global, unannounced_incoming_window,
          op->max_recv_bytes - stream_global->max_recv_bytes);
      stream_global->unannounced_incoming_window += op->max_recv_bytes - stream_global->max_recv_bytes;
      stream_global->max_recv_bytes = op->max_recv_bytes;
    }
    grpc_chttp2_incoming_metadata_live_op_buffer_end(
        &stream_global->outstanding_metadata);
    if (stream_global->id != 0) {
      grpc_chttp2_list_add_read_write_state_changed(transport_global,
                                                    stream_global);
      grpc_chttp2_list_add_writable_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);
  }
}
Example #7
0
int grpc_chttp2_unlocking_check_writes(
    grpc_chttp2_transport_global *transport_global,
    grpc_chttp2_transport_writing *transport_writing) {
    grpc_chttp2_stream_global *stream_global;
    grpc_chttp2_stream_writing *stream_writing;
    grpc_chttp2_stream_global *first_reinserted_stream = NULL;
    gpr_uint32 window_delta;

    /* simple writes are queued to qbuf, and flushed here */
    gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf);
    GPR_ASSERT(transport_global->qbuf.count == 0);

    if (transport_global->dirtied_local_settings &&
            !transport_global->sent_local_settings) {
        gpr_slice_buffer_add(
            &transport_writing->outbuf,
            grpc_chttp2_settings_create(
                transport_global->settings[GRPC_SENT_SETTINGS],
                transport_global->settings[GRPC_LOCAL_SETTINGS],
                transport_global->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS));
        transport_global->force_send_settings = 0;
        transport_global->dirtied_local_settings = 0;
        transport_global->sent_local_settings = 1;
    }

    /* for each grpc_chttp2_stream that's become writable, frame it's data
       (according to available window sizes) and add to the output buffer */
    while (grpc_chttp2_list_pop_writable_stream(
                transport_global, transport_writing, &stream_global, &stream_writing)) {
        if (stream_global == first_reinserted_stream) {
            /* prevent infinite loop */
            grpc_chttp2_list_add_first_writable_stream(transport_global,
                    stream_global);
            break;
        }

        stream_writing->id = stream_global->id;
        stream_writing->send_closed = GRPC_DONT_SEND_CLOSED;

        if (stream_global->outgoing_sopb) {
            window_delta =
                grpc_chttp2_preencode(stream_global->outgoing_sopb->ops,
                                      &stream_global->outgoing_sopb->nops,
                                      GPR_MIN(transport_global->outgoing_window,
                                              stream_global->outgoing_window),
                                      &stream_writing->sopb);
            GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT(
                "write", transport_global, outgoing_window, -(gpr_int64)window_delta);
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
                                             outgoing_window,
                                             -(gpr_int64)window_delta);
            transport_global->outgoing_window -= window_delta;
            stream_global->outgoing_window -= window_delta;

            if (stream_global->write_state == GRPC_WRITE_STATE_QUEUED_CLOSE &&
                    stream_global->outgoing_sopb->nops == 0) {
                if (!transport_global->is_client && !stream_global->read_closed) {
                    stream_writing->send_closed = GRPC_SEND_CLOSED_WITH_RST_STREAM;
                } else {
                    stream_writing->send_closed = GRPC_SEND_CLOSED;
                }
            }

            if (stream_global->outgoing_window > 0 &&
                    stream_global->outgoing_sopb->nops != 0) {
                grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
                if (first_reinserted_stream == NULL &&
                        transport_global->outgoing_window == 0) {
                    first_reinserted_stream = stream_global;
                }
            }
        }

        if (!stream_global->read_closed && stream_global->unannounced_incoming_window > 0) {
            stream_writing->announce_window = stream_global->unannounced_incoming_window;
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
                                             incoming_window, stream_global->unannounced_incoming_window);
            GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global,
                                             unannounced_incoming_window, -(gpr_int64)stream_global->unannounced_incoming_window);
            stream_global->incoming_window += stream_global->unannounced_incoming_window;
            stream_global->unannounced_incoming_window = 0;
            grpc_chttp2_list_add_incoming_window_updated(transport_global,
                    stream_global);
            stream_global->writing_now |= GRPC_CHTTP2_WRITING_WINDOW;
        }
        if (stream_writing->sopb.nops > 0 ||
                stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) {
            stream_global->writing_now |= GRPC_CHTTP2_WRITING_DATA;
        }
        if (stream_global->writing_now != 0) {
            grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
        }
    }

    /* if the grpc_chttp2_transport is ready to send a window update, do so here
       also; 3/4 is a magic number that will likely get tuned soon */
    if (transport_global->incoming_window <
            transport_global->connection_window_target * 3 / 4) {
        window_delta = transport_global->connection_window_target -
                       transport_global->incoming_window;
        gpr_slice_buffer_add(&transport_writing->outbuf,
                             grpc_chttp2_window_update_create(0, window_delta));
        GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT("write", transport_global,
                                            incoming_window, window_delta);
        transport_global->incoming_window += window_delta;
    }

    return transport_writing->outbuf.count > 0 ||
           grpc_chttp2_list_have_writing_streams(transport_writing);
}
Example #8
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);
        }
    }
}