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; } } }
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; }
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); }
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); } } }