Esempio n. 1
0
static void flush_write_staging_buffer(secure_endpoint *ep, uint8_t **cur,
                                       uint8_t **end) {
  grpc_slice_buffer_add(&ep->output_buffer, ep->write_staging_buffer);
  ep->write_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE);
  *cur = GRPC_SLICE_START_PTR(ep->write_staging_buffer);
  *end = GRPC_SLICE_END_PTR(ep->write_staging_buffer);
}
Esempio n. 2
0
static void flush_read_staging_buffer(secure_endpoint *ep, uint8_t **cur,
                                      uint8_t **end) {
  grpc_slice_buffer_add(ep->read_buffer, ep->read_staging_buffer);
  ep->read_staging_buffer = GRPC_SLICE_MALLOC(STAGING_BUFFER_SIZE);
  *cur = GRPC_SLICE_START_PTR(ep->read_staging_buffer);
  *end = GRPC_SLICE_END_PTR(ep->read_staging_buffer);
}
Esempio n. 3
0
grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
                                          grpc_chttp2_transport *t,
                                          grpc_chttp2_stream *s,
                                          grpc_slice slice, int is_last) {
  uint8_t *const beg = GRPC_SLICE_START_PTR(slice);
  uint8_t *const end = GRPC_SLICE_END_PTR(slice);
  uint8_t *cur = beg;
  grpc_chttp2_ping_parser *p = parser;

  while (p->byte != 8 && cur != end) {
    p->opaque_8bytes[p->byte] = *cur;
    cur++;
    p->byte++;
  }

  if (p->byte == 8) {
    GPR_ASSERT(is_last);
    if (p->is_ack) {
      grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes);
    } else {
      grpc_slice_buffer_add(&t->qbuf,
                            grpc_chttp2_ping_create(1, p->opaque_8bytes));
      grpc_chttp2_initiate_write(exec_ctx, t, false, "ping response");
    }
  }

  return GRPC_ERROR_NONE;
}
Esempio n. 4
0
grpc_error *grpc_chttp2_window_update_parser_parse(
    grpc_exec_ctx *exec_ctx, void *parser, grpc_chttp2_transport *t,
    grpc_chttp2_stream *s, grpc_slice slice, int is_last) {
  uint8_t *const beg = GRPC_SLICE_START_PTR(slice);
  uint8_t *const end = GRPC_SLICE_END_PTR(slice);
  uint8_t *cur = beg;
  grpc_chttp2_window_update_parser *p = parser;

  while (p->byte != 4 && cur != end) {
    p->amount |= ((uint32_t)*cur) << (8 * (3 - p->byte));
    cur++;
    p->byte++;
  }

  if (s != NULL) {
    s->stats.incoming.framing_bytes += (uint32_t)(end - cur);
  }

  if (p->byte == 4) {
    uint32_t received_update = p->amount;
    if (received_update == 0 || (received_update & 0x80000000u)) {
      char *msg;
      gpr_asprintf(&msg, "invalid window update bytes: %d", p->amount);
      grpc_error *err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
      gpr_free(msg);
      return err;
    }
    GPR_ASSERT(is_last);

    if (t->incoming_stream_id != 0) {
      if (s != NULL) {
        GRPC_CHTTP2_FLOW_CREDIT_STREAM("parse", t, s, outgoing_window_delta,
                                       received_update);
        if (grpc_chttp2_list_remove_stalled_by_stream(t, s)) {
          grpc_chttp2_become_writable(
              exec_ctx, t, s, GRPC_CHTTP2_STREAM_WRITE_INITIATE_UNCOVERED,
              "stream.read_flow_control");
        }
      }
    } else {
      bool was_zero = t->outgoing_window <= 0;
      GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parse", t, outgoing_window,
                                        received_update);
      bool is_zero = t->outgoing_window <= 0;
      if (was_zero && !is_zero) {
        grpc_chttp2_initiate_write(exec_ctx, t, "new_global_flow_control");
      }
    }
  }

  return GRPC_ERROR_NONE;
}
Esempio n. 5
0
static grpc_error *conforms_to(grpc_slice slice, const uint8_t *legal_bits,
                               const char *err_desc) {
  const uint8_t *p = GRPC_SLICE_START_PTR(slice);
  const uint8_t *e = GRPC_SLICE_END_PTR(slice);
  for (; p != e; p++) {
    int idx = *p;
    int byte = idx / 8;
    int bit = idx % 8;
    if ((legal_bits[byte] & (1 << bit)) == 0) {
      char *dump = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
      grpc_error *error = grpc_error_set_str(
          grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(err_desc),
                             GRPC_ERROR_INT_OFFSET,
                             p - GRPC_SLICE_START_PTR(slice)),
          GRPC_ERROR_STR_RAW_BYTES, grpc_slice_from_copied_string(dump));
      gpr_free(dump);
      return error;
    }
  }
  return GRPC_ERROR_NONE;
}
Esempio n. 6
0
static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
                           grpc_slice_buffer *slices, grpc_closure *cb) {
  GPR_TIMER_BEGIN("secure_endpoint.endpoint_write", 0);

  unsigned i;
  tsi_result result = TSI_OK;
  secure_endpoint *ep = (secure_endpoint *)secure_ep;
  uint8_t *cur = GRPC_SLICE_START_PTR(ep->write_staging_buffer);
  uint8_t *end = GRPC_SLICE_END_PTR(ep->write_staging_buffer);

  grpc_slice_buffer_reset_and_unref(&ep->output_buffer);

  if (grpc_trace_secure_endpoint) {
    for (i = 0; i < slices->count; i++) {
      char *data =
          grpc_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
      gpr_log(GPR_DEBUG, "WRITE %p: %s", ep, data);
      gpr_free(data);
    }
  }

  for (i = 0; i < slices->count; i++) {
    grpc_slice plain = slices->slices[i];
    uint8_t *message_bytes = GRPC_SLICE_START_PTR(plain);
    size_t message_size = GRPC_SLICE_LENGTH(plain);
    while (message_size > 0) {
      size_t protected_buffer_size_to_send = (size_t)(end - cur);
      size_t processed_message_size = message_size;
      gpr_mu_lock(&ep->protector_mu);
      result = tsi_frame_protector_protect(ep->protector, message_bytes,
                                           &processed_message_size, cur,
                                           &protected_buffer_size_to_send);
      gpr_mu_unlock(&ep->protector_mu);
      if (result != TSI_OK) {
        gpr_log(GPR_ERROR, "Encryption error: %s",
                tsi_result_to_string(result));
        break;
      }
      message_bytes += processed_message_size;
      message_size -= processed_message_size;
      cur += protected_buffer_size_to_send;

      if (cur == end) {
        flush_write_staging_buffer(ep, &cur, &end);
      }
    }
    if (result != TSI_OK) break;
  }
  if (result == TSI_OK) {
    size_t still_pending_size;
    do {
      size_t protected_buffer_size_to_send = (size_t)(end - cur);
      gpr_mu_lock(&ep->protector_mu);
      result = tsi_frame_protector_protect_flush(ep->protector, cur,
                                                 &protected_buffer_size_to_send,
                                                 &still_pending_size);
      gpr_mu_unlock(&ep->protector_mu);
      if (result != TSI_OK) break;
      cur += protected_buffer_size_to_send;
      if (cur == end) {
        flush_write_staging_buffer(ep, &cur, &end);
      }
    } while (still_pending_size > 0);
    if (cur != GRPC_SLICE_START_PTR(ep->write_staging_buffer)) {
      grpc_slice_buffer_add(
          &ep->output_buffer,
          grpc_slice_split_head(
              &ep->write_staging_buffer,
              (size_t)(cur - GRPC_SLICE_START_PTR(ep->write_staging_buffer))));
    }
  }

  if (result != TSI_OK) {
    /* TODO(yangg) do different things according to the error type? */
    grpc_slice_buffer_reset_and_unref(&ep->output_buffer);
    grpc_exec_ctx_sched(
        exec_ctx, cb,
        grpc_set_tsi_error_result(GRPC_ERROR_CREATE("Wrap failed"), result),
        NULL);
    GPR_TIMER_END("secure_endpoint.endpoint_write", 0);
    return;
  }

  grpc_endpoint_write(exec_ctx, ep->wrapped_ep, &ep->output_buffer, cb);
  GPR_TIMER_END("secure_endpoint.endpoint_write", 0);
}
Esempio n. 7
0
static void on_read(grpc_exec_ctx *exec_ctx, void *user_data,
                    grpc_error *error) {
  unsigned i;
  uint8_t keep_looping = 0;
  tsi_result result = TSI_OK;
  secure_endpoint *ep = (secure_endpoint *)user_data;
  uint8_t *cur = GRPC_SLICE_START_PTR(ep->read_staging_buffer);
  uint8_t *end = GRPC_SLICE_END_PTR(ep->read_staging_buffer);

  if (error != GRPC_ERROR_NONE) {
    grpc_slice_buffer_reset_and_unref(ep->read_buffer);
    call_read_cb(exec_ctx, ep, GRPC_ERROR_CREATE_REFERENCING(
                                   "Secure read failed", &error, 1));
    return;
  }

  /* TODO(yangg) check error, maybe bail out early */
  for (i = 0; i < ep->source_buffer.count; i++) {
    grpc_slice encrypted = ep->source_buffer.slices[i];
    uint8_t *message_bytes = GRPC_SLICE_START_PTR(encrypted);
    size_t message_size = GRPC_SLICE_LENGTH(encrypted);

    while (message_size > 0 || keep_looping) {
      size_t unprotected_buffer_size_written = (size_t)(end - cur);
      size_t processed_message_size = message_size;
      gpr_mu_lock(&ep->protector_mu);
      result = tsi_frame_protector_unprotect(ep->protector, message_bytes,
                                             &processed_message_size, cur,
                                             &unprotected_buffer_size_written);
      gpr_mu_unlock(&ep->protector_mu);
      if (result != TSI_OK) {
        gpr_log(GPR_ERROR, "Decryption error: %s",
                tsi_result_to_string(result));
        break;
      }
      message_bytes += processed_message_size;
      message_size -= processed_message_size;
      cur += unprotected_buffer_size_written;

      if (cur == end) {
        flush_read_staging_buffer(ep, &cur, &end);
        /* Force to enter the loop again to extract buffered bytes in protector.
           The bytes could be buffered because of running out of staging_buffer.
           If this happens at the end of all slices, doing another unprotect
           avoids leaving data in the protector. */
        keep_looping = 1;
      } else if (unprotected_buffer_size_written > 0) {
        keep_looping = 1;
      } else {
        keep_looping = 0;
      }
    }
    if (result != TSI_OK) break;
  }

  if (cur != GRPC_SLICE_START_PTR(ep->read_staging_buffer)) {
    grpc_slice_buffer_add(
        ep->read_buffer,
        grpc_slice_split_head(
            &ep->read_staging_buffer,
            (size_t)(cur - GRPC_SLICE_START_PTR(ep->read_staging_buffer))));
  }

  /* TODO(yangg) experiment with moving this block after read_cb to see if it
     helps latency */
  grpc_slice_buffer_reset_and_unref(&ep->source_buffer);

  if (result != TSI_OK) {
    grpc_slice_buffer_reset_and_unref(ep->read_buffer);
    call_read_cb(exec_ctx, ep, grpc_set_tsi_error_result(
                                   GRPC_ERROR_CREATE("Unwrap failed"), result));
    return;
  }

  call_read_cb(exec_ctx, ep, GRPC_ERROR_NONE);
}
Esempio n. 8
0
grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
                                     grpc_chttp2_transport *t,
                                     grpc_slice slice) {
  uint8_t *beg = GRPC_SLICE_START_PTR(slice);
  uint8_t *end = GRPC_SLICE_END_PTR(slice);
  uint8_t *cur = beg;
  grpc_error *err;

  if (cur == end) return GRPC_ERROR_NONE;

  switch (t->deframe_state) {
    case GRPC_DTS_CLIENT_PREFIX_0:
    case GRPC_DTS_CLIENT_PREFIX_1:
    case GRPC_DTS_CLIENT_PREFIX_2:
    case GRPC_DTS_CLIENT_PREFIX_3:
    case GRPC_DTS_CLIENT_PREFIX_4:
    case GRPC_DTS_CLIENT_PREFIX_5:
    case GRPC_DTS_CLIENT_PREFIX_6:
    case GRPC_DTS_CLIENT_PREFIX_7:
    case GRPC_DTS_CLIENT_PREFIX_8:
    case GRPC_DTS_CLIENT_PREFIX_9:
    case GRPC_DTS_CLIENT_PREFIX_10:
    case GRPC_DTS_CLIENT_PREFIX_11:
    case GRPC_DTS_CLIENT_PREFIX_12:
    case GRPC_DTS_CLIENT_PREFIX_13:
    case GRPC_DTS_CLIENT_PREFIX_14:
    case GRPC_DTS_CLIENT_PREFIX_15:
    case GRPC_DTS_CLIENT_PREFIX_16:
    case GRPC_DTS_CLIENT_PREFIX_17:
    case GRPC_DTS_CLIENT_PREFIX_18:
    case GRPC_DTS_CLIENT_PREFIX_19:
    case GRPC_DTS_CLIENT_PREFIX_20:
    case GRPC_DTS_CLIENT_PREFIX_21:
    case GRPC_DTS_CLIENT_PREFIX_22:
    case GRPC_DTS_CLIENT_PREFIX_23:
      while (cur != end && t->deframe_state != GRPC_DTS_FH_0) {
        if (*cur != GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state]) {
          char *msg;
          gpr_asprintf(
              &msg,
              "Connect string mismatch: expected '%c' (%d) got '%c' (%d) "
              "at byte %d",
              GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state],
              (int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state],
              *cur, (int)*cur, t->deframe_state);
          err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
          gpr_free(msg);
          return err;
        }
        ++cur;
        t->deframe_state =
            (grpc_chttp2_deframe_transport_state)(1 + (int)t->deframe_state);
      }
      if (cur == end) {
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    dts_fh_0:
    case GRPC_DTS_FH_0:
      GPR_ASSERT(cur < end);
      t->incoming_frame_size = ((uint32_t)*cur) << 16;
      if (++cur == end) {
        t->deframe_state = GRPC_DTS_FH_1;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_DTS_FH_1:
      GPR_ASSERT(cur < end);
      t->incoming_frame_size |= ((uint32_t)*cur) << 8;
      if (++cur == end) {
        t->deframe_state = GRPC_DTS_FH_2;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_DTS_FH_2:
      GPR_ASSERT(cur < end);
      t->incoming_frame_size |= *cur;
      if (++cur == end) {
        t->deframe_state = GRPC_DTS_FH_3;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_DTS_FH_3:
      GPR_ASSERT(cur < end);
      t->incoming_frame_type = *cur;
      if (++cur == end) {
        t->deframe_state = GRPC_DTS_FH_4;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_DTS_FH_4:
      GPR_ASSERT(cur < end);
      t->incoming_frame_flags = *cur;
      if (++cur == end) {
        t->deframe_state = GRPC_DTS_FH_5;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_DTS_FH_5:
      GPR_ASSERT(cur < end);
      t->incoming_stream_id = (((uint32_t)*cur) & 0x7f) << 24;
      if (++cur == end) {
        t->deframe_state = GRPC_DTS_FH_6;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_DTS_FH_6:
      GPR_ASSERT(cur < end);
      t->incoming_stream_id |= ((uint32_t)*cur) << 16;
      if (++cur == end) {
        t->deframe_state = GRPC_DTS_FH_7;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_DTS_FH_7:
      GPR_ASSERT(cur < end);
      t->incoming_stream_id |= ((uint32_t)*cur) << 8;
      if (++cur == end) {
        t->deframe_state = GRPC_DTS_FH_8;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_DTS_FH_8:
      GPR_ASSERT(cur < end);
      t->incoming_stream_id |= ((uint32_t)*cur);
      t->deframe_state = GRPC_DTS_FRAME;
      err = init_frame_parser(exec_ctx, t);
      if (err != GRPC_ERROR_NONE) {
        return err;
      }
      if (t->incoming_frame_size == 0) {
        err = parse_frame_slice(exec_ctx, t, grpc_empty_slice(), 1);
        if (err != GRPC_ERROR_NONE) {
          return err;
        }
        t->incoming_stream = NULL;
        if (++cur == end) {
          t->deframe_state = GRPC_DTS_FH_0;
          return GRPC_ERROR_NONE;
        }
        goto dts_fh_0; /* loop */
      } else if (t->incoming_frame_size >
                 t->settings[GRPC_ACKED_SETTINGS]
                            [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]) {
        char *msg;
        gpr_asprintf(&msg, "Frame size %d is larger than max frame size %d",
                     t->incoming_frame_size,
                     t->settings[GRPC_ACKED_SETTINGS]
                                [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]);
        err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
        gpr_free(msg);
        return err;
      }
      if (++cur == end) {
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_DTS_FRAME:
      GPR_ASSERT(cur < end);
      if ((uint32_t)(end - cur) == t->incoming_frame_size) {
        err = parse_frame_slice(
            exec_ctx, t, grpc_slice_sub_no_ref(slice, (size_t)(cur - beg),
                                               (size_t)(end - beg)),
            1);
        if (err != GRPC_ERROR_NONE) {
          return err;
        }
        t->deframe_state = GRPC_DTS_FH_0;
        t->incoming_stream = NULL;
        return GRPC_ERROR_NONE;
      } else if ((uint32_t)(end - cur) > t->incoming_frame_size) {
        size_t cur_offset = (size_t)(cur - beg);
        err = parse_frame_slice(
            exec_ctx, t,
            grpc_slice_sub_no_ref(slice, cur_offset,
                                  cur_offset + t->incoming_frame_size),
            1);
        if (err != GRPC_ERROR_NONE) {
          return err;
        }
        cur += t->incoming_frame_size;
        t->incoming_stream = NULL;
        goto dts_fh_0; /* loop */
      } else {
        err = parse_frame_slice(
            exec_ctx, t, grpc_slice_sub_no_ref(slice, (size_t)(cur - beg),
                                               (size_t)(end - beg)),
            0);
        if (err != GRPC_ERROR_NONE) {
          return err;
        }
        t->incoming_frame_size -= (uint32_t)(end - cur);
        return GRPC_ERROR_NONE;
      }
      GPR_UNREACHABLE_CODE(return 0);
  }

  GPR_UNREACHABLE_CODE(return 0);
}
Esempio n. 9
0
int grpc_is_binary_header(grpc_slice slice) {
  if (GRPC_SLICE_LENGTH(slice) < 5) return 0;
  return 0 == memcmp(GRPC_SLICE_END_PTR(slice) - 4, "-bin", 4);
}
Esempio n. 10
0
static grpc_error *parse_inner(grpc_exec_ctx *exec_ctx,
                               grpc_chttp2_data_parser *p,
                               grpc_chttp2_transport *t, grpc_chttp2_stream *s,
                               grpc_slice slice) {
  uint8_t *const beg = GRPC_SLICE_START_PTR(slice);
  uint8_t *const end = GRPC_SLICE_END_PTR(slice);
  uint8_t *cur = beg;
  uint32_t message_flags;
  grpc_chttp2_incoming_byte_stream *incoming_byte_stream;
  char *msg;

  if (cur == end) {
    return GRPC_ERROR_NONE;
  }

  switch (p->state) {
    case GRPC_CHTTP2_DATA_ERROR:
      p->state = GRPC_CHTTP2_DATA_ERROR;
      return GRPC_ERROR_REF(p->error);
    fh_0:
    case GRPC_CHTTP2_DATA_FH_0:
      s->stats.incoming.framing_bytes++;
      p->frame_type = *cur;
      switch (p->frame_type) {
        case 0:
          p->is_frame_compressed = 0; /* GPR_FALSE */
          break;
        case 1:
          p->is_frame_compressed = 1; /* GPR_TRUE */
          break;
        default:
          gpr_asprintf(&msg, "Bad GRPC frame type 0x%02x", p->frame_type);
          p->error = GRPC_ERROR_CREATE(msg);
          p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID,
                                        (intptr_t)s->id);
          gpr_free(msg);
          msg = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
          p->error =
              grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES, msg);
          gpr_free(msg);
          p->error =
              grpc_error_set_int(p->error, GRPC_ERROR_INT_OFFSET, cur - beg);
          p->state = GRPC_CHTTP2_DATA_ERROR;
          return GRPC_ERROR_REF(p->error);
      }
      if (++cur == end) {
        p->state = GRPC_CHTTP2_DATA_FH_1;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_CHTTP2_DATA_FH_1:
      s->stats.incoming.framing_bytes++;
      p->frame_size = ((uint32_t)*cur) << 24;
      if (++cur == end) {
        p->state = GRPC_CHTTP2_DATA_FH_2;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_CHTTP2_DATA_FH_2:
      s->stats.incoming.framing_bytes++;
      p->frame_size |= ((uint32_t)*cur) << 16;
      if (++cur == end) {
        p->state = GRPC_CHTTP2_DATA_FH_3;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_CHTTP2_DATA_FH_3:
      s->stats.incoming.framing_bytes++;
      p->frame_size |= ((uint32_t)*cur) << 8;
      if (++cur == end) {
        p->state = GRPC_CHTTP2_DATA_FH_4;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_CHTTP2_DATA_FH_4:
      s->stats.incoming.framing_bytes++;
      p->frame_size |= ((uint32_t)*cur);
      p->state = GRPC_CHTTP2_DATA_FRAME;
      ++cur;
      message_flags = 0;
      if (p->is_frame_compressed) {
        message_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
      }
      p->parsing_frame = incoming_byte_stream =
          grpc_chttp2_incoming_byte_stream_create(exec_ctx, t, s, p->frame_size,
                                                  message_flags);
    /* fallthrough */
    case GRPC_CHTTP2_DATA_FRAME:
      if (cur == end) {
        return GRPC_ERROR_NONE;
      }
      uint32_t remaining = (uint32_t)(end - cur);
      if (remaining == p->frame_size) {
        s->stats.incoming.data_bytes += p->frame_size;
        grpc_chttp2_incoming_byte_stream_push(
            exec_ctx, p->parsing_frame,
            grpc_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
        grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame,
                                                  GRPC_ERROR_NONE);
        p->parsing_frame = NULL;
        p->state = GRPC_CHTTP2_DATA_FH_0;
        return GRPC_ERROR_NONE;
      } else if (remaining > p->frame_size) {
        s->stats.incoming.data_bytes += p->frame_size;
        grpc_chttp2_incoming_byte_stream_push(
            exec_ctx, p->parsing_frame,
            grpc_slice_sub(slice, (size_t)(cur - beg),
                           (size_t)(cur + p->frame_size - beg)));
        grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame,
                                                  GRPC_ERROR_NONE);
        p->parsing_frame = NULL;
        cur += p->frame_size;
        goto fh_0; /* loop */
      } else {
        GPR_ASSERT(remaining <= p->frame_size);
        grpc_chttp2_incoming_byte_stream_push(
            exec_ctx, p->parsing_frame,
            grpc_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
        p->frame_size -= remaining;
        s->stats.incoming.data_bytes += remaining;
        return GRPC_ERROR_NONE;
      }
  }

  GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
}
Esempio n. 11
0
grpc_error *grpc_deframe_unprocessed_incoming_frames(
    grpc_exec_ctx *exec_ctx, grpc_chttp2_data_parser *p, grpc_chttp2_stream *s,
    grpc_slice_buffer *slices, grpc_slice *slice_out,
    grpc_byte_stream **stream_out) {
  grpc_error *error = GRPC_ERROR_NONE;
  grpc_chttp2_transport *t = s->t;

  while (slices->count > 0) {
    uint8_t *beg = NULL;
    uint8_t *end = NULL;
    uint8_t *cur = NULL;

    grpc_slice slice = grpc_slice_buffer_take_first(slices);

    beg = GRPC_SLICE_START_PTR(slice);
    end = GRPC_SLICE_END_PTR(slice);
    cur = beg;
    uint32_t message_flags;
    char *msg;

    if (cur == end) {
      grpc_slice_unref_internal(exec_ctx, slice);
      continue;
    }

    switch (p->state) {
      case GRPC_CHTTP2_DATA_ERROR:
        p->state = GRPC_CHTTP2_DATA_ERROR;
        grpc_slice_unref_internal(exec_ctx, slice);
        return GRPC_ERROR_REF(p->error);
      case GRPC_CHTTP2_DATA_FH_0:
        p->frame_type = *cur;
        switch (p->frame_type) {
          case 0:
            p->is_frame_compressed = false; /* GPR_FALSE */
            break;
          case 1:
            p->is_frame_compressed = true; /* GPR_TRUE */
            break;
          default:
            gpr_asprintf(&msg, "Bad GRPC frame type 0x%02x", p->frame_type);
            p->error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
            p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID,
                                          (intptr_t)s->id);
            gpr_free(msg);
            msg = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
            p->error = grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES,
                                          grpc_slice_from_copied_string(msg));
            gpr_free(msg);
            p->error =
                grpc_error_set_int(p->error, GRPC_ERROR_INT_OFFSET, cur - beg);
            p->state = GRPC_CHTTP2_DATA_ERROR;
            grpc_slice_unref_internal(exec_ctx, slice);
            return GRPC_ERROR_REF(p->error);
        }
        if (++cur == end) {
          p->state = GRPC_CHTTP2_DATA_FH_1;
          grpc_slice_unref_internal(exec_ctx, slice);
          continue;
        }
      /* fallthrough */
      case GRPC_CHTTP2_DATA_FH_1:
        p->frame_size = ((uint32_t)*cur) << 24;
        if (++cur == end) {
          p->state = GRPC_CHTTP2_DATA_FH_2;
          grpc_slice_unref_internal(exec_ctx, slice);
          continue;
        }
      /* fallthrough */
      case GRPC_CHTTP2_DATA_FH_2:
        p->frame_size |= ((uint32_t)*cur) << 16;
        if (++cur == end) {
          p->state = GRPC_CHTTP2_DATA_FH_3;
          grpc_slice_unref_internal(exec_ctx, slice);
          continue;
        }
      /* fallthrough */
      case GRPC_CHTTP2_DATA_FH_3:
        p->frame_size |= ((uint32_t)*cur) << 8;
        if (++cur == end) {
          p->state = GRPC_CHTTP2_DATA_FH_4;
          grpc_slice_unref_internal(exec_ctx, slice);
          continue;
        }
      /* fallthrough */
      case GRPC_CHTTP2_DATA_FH_4:
        GPR_ASSERT(stream_out != NULL);
        GPR_ASSERT(p->parsing_frame == NULL);
        p->frame_size |= ((uint32_t)*cur);
        p->state = GRPC_CHTTP2_DATA_FRAME;
        ++cur;
        message_flags = 0;
        if (p->is_frame_compressed) {
          message_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
        }
        p->parsing_frame = grpc_chttp2_incoming_byte_stream_create(
            exec_ctx, t, s, p->frame_size, message_flags);
        *stream_out = &p->parsing_frame->base;
        if (p->parsing_frame->remaining_bytes == 0) {
          GRPC_ERROR_UNREF(grpc_chttp2_incoming_byte_stream_finished(
              exec_ctx, p->parsing_frame, GRPC_ERROR_NONE, true));
          p->parsing_frame = NULL;
          p->state = GRPC_CHTTP2_DATA_FH_0;
        }
        s->pending_byte_stream = true;

        if (cur != end) {
          grpc_slice_buffer_undo_take_first(
              &s->unprocessed_incoming_frames_buffer,
              grpc_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
        }
        grpc_slice_unref_internal(exec_ctx, slice);
        return GRPC_ERROR_NONE;
      case GRPC_CHTTP2_DATA_FRAME: {
        GPR_ASSERT(p->parsing_frame != NULL);
        GPR_ASSERT(slice_out != NULL);
        if (cur == end) {
          grpc_slice_unref_internal(exec_ctx, slice);
          continue;
        }
        uint32_t remaining = (uint32_t)(end - cur);
        if (remaining == p->frame_size) {
          if (GRPC_ERROR_NONE != (error = grpc_chttp2_incoming_byte_stream_push(
                                      exec_ctx, p->parsing_frame,
                                      grpc_slice_sub(slice, (size_t)(cur - beg),
                                                     (size_t)(end - beg)),
                                      slice_out))) {
            grpc_slice_unref_internal(exec_ctx, slice);
            return error;
          }
          if (GRPC_ERROR_NONE !=
              (error = grpc_chttp2_incoming_byte_stream_finished(
                   exec_ctx, p->parsing_frame, GRPC_ERROR_NONE, true))) {
            grpc_slice_unref_internal(exec_ctx, slice);
            return error;
          }
          p->parsing_frame = NULL;
          p->state = GRPC_CHTTP2_DATA_FH_0;
          grpc_slice_unref_internal(exec_ctx, slice);
          return GRPC_ERROR_NONE;
        } else if (remaining < p->frame_size) {
          if (GRPC_ERROR_NONE != (error = grpc_chttp2_incoming_byte_stream_push(
                                      exec_ctx, p->parsing_frame,
                                      grpc_slice_sub(slice, (size_t)(cur - beg),
                                                     (size_t)(end - beg)),
                                      slice_out))) {
            return error;
          }
          p->frame_size -= remaining;
          grpc_slice_unref_internal(exec_ctx, slice);
          return GRPC_ERROR_NONE;
        } else {
          GPR_ASSERT(remaining > p->frame_size);
          if (GRPC_ERROR_NONE !=
              (grpc_chttp2_incoming_byte_stream_push(
                  exec_ctx, p->parsing_frame,
                  grpc_slice_sub(slice, (size_t)(cur - beg),
                                 (size_t)(cur + p->frame_size - beg)),
                  slice_out))) {
            grpc_slice_unref_internal(exec_ctx, slice);
            return error;
          }
          if (GRPC_ERROR_NONE !=
              (error = grpc_chttp2_incoming_byte_stream_finished(
                   exec_ctx, p->parsing_frame, GRPC_ERROR_NONE, true))) {
            grpc_slice_unref_internal(exec_ctx, slice);
            return error;
          }
          p->parsing_frame = NULL;
          p->state = GRPC_CHTTP2_DATA_FH_0;
          cur += p->frame_size;
          grpc_slice_buffer_undo_take_first(
              &s->unprocessed_incoming_frames_buffer,
              grpc_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
          grpc_slice_unref_internal(exec_ctx, slice);
          return GRPC_ERROR_NONE;
        }
      }
    }
  }

  return GRPC_ERROR_NONE;
}