示例#1
0
static void maybe_start_some_streams(
    grpc_chttp2_transport_global *transport_global) {
  grpc_chttp2_stream_global *stream_global;
  /* start streams where we have free grpc_chttp2_stream ids and free
   * concurrency */
  while (transport_global->next_stream_id <= MAX_CLIENT_STREAM_ID &&
         transport_global->concurrent_stream_count <
             transport_global
                 ->settings[GRPC_PEER_SETTINGS]
                           [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] &&
         grpc_chttp2_list_pop_waiting_for_concurrency(transport_global,
                                                      &stream_global)) {
    GRPC_CHTTP2_IF_TRACING(gpr_log(
        GPR_DEBUG, "HTTP:%s: Allocating new grpc_chttp2_stream %p to id %d",
        transport_global->is_client ? "CLI" : "SVR", stream_global,
        transport_global->next_stream_id));

    GPR_ASSERT(stream_global->id == 0);
    stream_global->id = transport_global->next_stream_id;
    transport_global->next_stream_id += 2;

    if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) {
      grpc_chttp2_add_incoming_goaway(
          transport_global, GRPC_CHTTP2_NO_ERROR,
          gpr_slice_from_copied_string("Exceeded sequence number limit"));
    }

    stream_global->outgoing_window =
        transport_global->settings[GRPC_PEER_SETTINGS]
                                  [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
    stream_global->incoming_window =
        transport_global->settings[GRPC_SENT_SETTINGS]
                                  [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
    grpc_chttp2_stream_map_add(
        &TRANSPORT_FROM_GLOBAL(transport_global)->new_stream_map,
        stream_global->id, STREAM_FROM_GLOBAL(stream_global));
    stream_global->in_stream_map = 1;
    transport_global->concurrent_stream_count++;
    grpc_chttp2_list_add_incoming_window_updated(transport_global,
                                                 stream_global);
    grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
  }
  /* cancel out streams that will never be started */
  while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID &&
         grpc_chttp2_list_pop_waiting_for_concurrency(transport_global,
                                                      &stream_global)) {
    cancel_from_api(transport_global, stream_global, GRPC_STATUS_UNAVAILABLE);
  }
}
示例#2
0
文件: parsing.c 项目: xincun/grpc
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);
        }
    }
}
void grpc_chttp2_publish_reads(
    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
    grpc_chttp2_transport_parsing *transport_parsing) {
  grpc_chttp2_stream_global *stream_global;
  grpc_chttp2_stream_parsing *stream_parsing;
  int was_zero;
  int is_zero;

  /* 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->last_incoming_stream_id;
  }

  /* 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(uint32_t));
    transport_parsing->settings_ack_received = 0;
    transport_global->sent_local_settings = 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(exec_ctx, transport_global,
                                    (uint32_t)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 */
  was_zero = transport_global->outgoing_window <= 0;
  GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("parsed", transport_global, outgoing_window,
                                  transport_parsing, outgoing_window);
  is_zero = transport_global->outgoing_window <= 0;
  if (was_zero && !is_zero) {
    while (grpc_chttp2_list_pop_stalled_by_transport(transport_global,
                                                     &stream_global)) {
      grpc_chttp2_become_writable(transport_global, stream_global);
    }
  }

  if (transport_parsing->incoming_window <
      transport_global->connection_window_target * 3 / 4) {
    int64_t announce_bytes = transport_global->connection_window_target -
                             transport_parsing->incoming_window;
    GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_global,
                                      announce_incoming_window, announce_bytes);
    GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_parsing,
                                      incoming_window, announce_bytes);
  }

  /* 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)) {
    if (stream_parsing->seen_error) {
      stream_global->seen_error = true;
      stream_global->exceeded_metadata_size =
          stream_parsing->exceeded_metadata_size;
      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
    }

    /* flush stats to global stream state */
    grpc_transport_move_stats(&stream_parsing->stats, &stream_global->stats);

    /* update outgoing flow control window */
    was_zero = stream_global->outgoing_window <= 0;
    GRPC_CHTTP2_FLOW_MOVE_STREAM("parsed", transport_global, stream_global,
                                 outgoing_window, stream_parsing,
                                 outgoing_window);
    is_zero = stream_global->outgoing_window <= 0;
    if (was_zero && !is_zero) {
      grpc_chttp2_become_writable(transport_global, stream_global);
    }

    stream_global->max_recv_bytes -= (uint32_t)GPR_MIN(
        stream_global->max_recv_bytes, stream_parsing->received_bytes);
    stream_parsing->received_bytes = 0;

    /* publish incoming stream ops */
    if (stream_global->incoming_frames.tail != NULL) {
      stream_global->incoming_frames.tail->is_tail = 0;
    }
    if (stream_parsing->data_parser.incoming_frames.head != NULL) {
      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
    }
    grpc_chttp2_incoming_frame_queue_merge(
        &stream_global->incoming_frames,
        &stream_parsing->data_parser.incoming_frames);
    if (stream_global->incoming_frames.tail != NULL) {
      stream_global->incoming_frames.tail->is_tail = 1;
    }

    if (!stream_global->published_initial_metadata &&
        stream_parsing->got_metadata_on_parse[0]) {
      stream_parsing->got_metadata_on_parse[0] = 0;
      stream_global->published_initial_metadata = 1;
      GPR_SWAP(grpc_chttp2_incoming_metadata_buffer,
               stream_parsing->metadata_buffer[0],
               stream_global->received_initial_metadata);
      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
    }
    if (!stream_global->published_trailing_metadata &&
        stream_parsing->got_metadata_on_parse[1]) {
      stream_parsing->got_metadata_on_parse[1] = 0;
      stream_global->published_trailing_metadata = 1;
      GPR_SWAP(grpc_chttp2_incoming_metadata_buffer,
               stream_parsing->metadata_buffer[1],
               stream_global->received_trailing_metadata);
      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
    }

    if (stream_parsing->forced_close_error != GRPC_ERROR_NONE) {
      intptr_t reason;
      bool has_reason = grpc_error_get_int(stream_parsing->forced_close_error,
                                           GRPC_ERROR_INT_HTTP2_ERROR, &reason);
      if (has_reason && reason != GRPC_CHTTP2_NO_ERROR) {
        grpc_status_code status_code =
            has_reason
                ? grpc_chttp2_http2_error_to_grpc_status(
                      (grpc_chttp2_error_code)reason, stream_global->deadline)
                : GRPC_STATUS_INTERNAL;
        const char *status_details =
            grpc_error_string(stream_parsing->forced_close_error);
        gpr_slice slice_details = gpr_slice_from_copied_string(status_details);
        grpc_error_free_string(status_details);
        grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global,
                                status_code, &slice_details);
      }
      grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
                                     1, 1, stream_parsing->forced_close_error);
    }

    if (stream_parsing->received_close) {
      grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
                                     1, 0, GRPC_ERROR_NONE);
    }
  }
}
示例#4
0
grpc_error *grpc_chttp2_goaway_parser_parse(grpc_exec_ctx *exec_ctx,
                                            void *parser,
                                            grpc_chttp2_transport *t,
                                            grpc_chttp2_stream *s,
                                            gpr_slice slice, int is_last) {
  uint8_t *const beg = GPR_SLICE_START_PTR(slice);
  uint8_t *const end = GPR_SLICE_END_PTR(slice);
  uint8_t *cur = beg;
  grpc_chttp2_goaway_parser *p = parser;

  switch (p->state) {
    case GRPC_CHTTP2_GOAWAY_LSI0:
      if (cur == end) {
        p->state = GRPC_CHTTP2_GOAWAY_LSI0;
        return GRPC_ERROR_NONE;
      }
      p->last_stream_id = ((uint32_t)*cur) << 24;
      ++cur;
    /* fallthrough */
    case GRPC_CHTTP2_GOAWAY_LSI1:
      if (cur == end) {
        p->state = GRPC_CHTTP2_GOAWAY_LSI1;
        return GRPC_ERROR_NONE;
      }
      p->last_stream_id |= ((uint32_t)*cur) << 16;
      ++cur;
    /* fallthrough */
    case GRPC_CHTTP2_GOAWAY_LSI2:
      if (cur == end) {
        p->state = GRPC_CHTTP2_GOAWAY_LSI2;
        return GRPC_ERROR_NONE;
      }
      p->last_stream_id |= ((uint32_t)*cur) << 8;
      ++cur;
    /* fallthrough */
    case GRPC_CHTTP2_GOAWAY_LSI3:
      if (cur == end) {
        p->state = GRPC_CHTTP2_GOAWAY_LSI3;
        return GRPC_ERROR_NONE;
      }
      p->last_stream_id |= ((uint32_t)*cur);
      ++cur;
    /* fallthrough */
    case GRPC_CHTTP2_GOAWAY_ERR0:
      if (cur == end) {
        p->state = GRPC_CHTTP2_GOAWAY_ERR0;
        return GRPC_ERROR_NONE;
      }
      p->error_code = ((uint32_t)*cur) << 24;
      ++cur;
    /* fallthrough */
    case GRPC_CHTTP2_GOAWAY_ERR1:
      if (cur == end) {
        p->state = GRPC_CHTTP2_GOAWAY_ERR1;
        return GRPC_ERROR_NONE;
      }
      p->error_code |= ((uint32_t)*cur) << 16;
      ++cur;
    /* fallthrough */
    case GRPC_CHTTP2_GOAWAY_ERR2:
      if (cur == end) {
        p->state = GRPC_CHTTP2_GOAWAY_ERR2;
        return GRPC_ERROR_NONE;
      }
      p->error_code |= ((uint32_t)*cur) << 8;
      ++cur;
    /* fallthrough */
    case GRPC_CHTTP2_GOAWAY_ERR3:
      if (cur == end) {
        p->state = GRPC_CHTTP2_GOAWAY_ERR3;
        return GRPC_ERROR_NONE;
      }
      p->error_code |= ((uint32_t)*cur);
      ++cur;
    /* fallthrough */
    case GRPC_CHTTP2_GOAWAY_DEBUG:
      if (end != cur)
        memcpy(p->debug_data + p->debug_pos, cur, (size_t)(end - cur));
      GPR_ASSERT((size_t)(end - cur) < UINT32_MAX - p->debug_pos);
      p->debug_pos += (uint32_t)(end - cur);
      p->state = GRPC_CHTTP2_GOAWAY_DEBUG;
      if (is_last) {
        grpc_chttp2_add_incoming_goaway(
            exec_ctx, t, (uint32_t)p->error_code,
            gpr_slice_new(p->debug_data, p->debug_length, gpr_free));
        p->debug_data = NULL;
      }
      return GRPC_ERROR_NONE;
  }
  GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
}