Example #1
0
gpr_slice gpr_percent_encode_slice(gpr_slice slice,
                                   const uint8_t *unreserved_bytes) {
  static const uint8_t hex[] = "0123456789ABCDEF";

  // first pass: count the number of bytes needed to output this string
  size_t output_length = 0;
  const uint8_t *slice_start = GPR_SLICE_START_PTR(slice);
  const uint8_t *slice_end = GPR_SLICE_END_PTR(slice);
  const uint8_t *p;
  bool any_reserved_bytes = false;
  for (p = slice_start; p < slice_end; p++) {
    bool unres = is_unreserved_character(*p, unreserved_bytes);
    output_length += unres ? 1 : 3;
    any_reserved_bytes |= !unres;
  }
  // no unreserved bytes: return the string unmodified
  if (!any_reserved_bytes) {
    return gpr_slice_ref(slice);
  }
  // second pass: actually encode
  gpr_slice out = gpr_slice_malloc(output_length);
  uint8_t *q = GPR_SLICE_START_PTR(out);
  for (p = slice_start; p < slice_end; p++) {
    if (is_unreserved_character(*p, unreserved_bytes)) {
      *q++ = *p;
    } else {
      *q++ = '%';
      *q++ = hex[*p >> 4];
      *q++ = hex[*p & 15];
    }
  }
  GPR_ASSERT(q == GPR_SLICE_END_PTR(out));
  return out;
}
Example #2
0
grpc_error *grpc_chttp2_ping_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_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 {
      gpr_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;
}
Example #3
0
grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
    grpc_exec_ctx *exec_ctx, void *parser,
    grpc_chttp2_transport_parsing *transport_parsing,
    grpc_chttp2_stream_parsing *stream_parsing, 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_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, transport_parsing, p->opaque_8bytes);
    } else {
      gpr_slice_buffer_add(&transport_parsing->qbuf,
                           grpc_chttp2_ping_create(1, p->opaque_8bytes));
    }
  }

  return GRPC_CHTTP2_PARSE_OK;
}
Example #4
0
grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse(
    grpc_exec_ctx *exec_ctx, void *parser,
    grpc_chttp2_transport_parsing *transport_parsing,
    grpc_chttp2_stream_parsing *stream_parsing, 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_rst_stream_parser *p = parser;

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

  if (p->byte == 4) {
    GPR_ASSERT(is_last);
    stream_parsing->received_close = 1;
    stream_parsing->saw_rst_stream = 1;
    stream_parsing->rst_stream_reason = (((uint32_t)p->reason_bytes[0]) << 24) |
                                        (((uint32_t)p->reason_bytes[1]) << 16) |
                                        (((uint32_t)p->reason_bytes[2]) << 8) |
                                        (((uint32_t)p->reason_bytes[3]));
  }

  return GRPC_CHTTP2_PARSE_OK;
}
Example #5
0
static void flush_read_staging_buffer(secure_endpoint *ep, gpr_uint8 **cur,
                                      gpr_uint8 **end) {
  gpr_slice_buffer_add(&ep->input_buffer, ep->read_staging_buffer);
  ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
  *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer);
  *end = GPR_SLICE_END_PTR(ep->read_staging_buffer);
}
Example #6
0
static void test_vector(grpc_chttp2_hpack_parser *parser,
                        grpc_slice_split_mode mode, const char *hexstring,
                        ... /* char *key, char *value */) {
  gpr_slice input = parse_hexstring(hexstring);
  gpr_slice *slices;
  size_t nslices;
  size_t i;
  test_checker chk;

  va_start(chk.args, hexstring);

  parser->on_header = onhdr;
  parser->on_header_user_data = &chk;

  grpc_split_slices(mode, &input, 1, &slices, &nslices);
  gpr_slice_unref(input);

  for (i = 0; i < nslices; i++) {
    GPR_ASSERT(grpc_chttp2_hpack_parser_parse(
        parser, GPR_SLICE_START_PTR(slices[i]), GPR_SLICE_END_PTR(slices[i])));
  }

  for (i = 0; i < nslices; i++) {
    gpr_slice_unref(slices[i]);
  }
  gpr_free(slices);

  GPR_ASSERT(NULL == va_arg(chk.args, char *));

  va_end(chk.args);
}
Example #7
0
static void flush_write_staging_buffer(secure_endpoint *ep, uint8_t **cur,
                                       uint8_t **end) {
  gpr_slice_buffer_add(&ep->output_buffer, ep->write_staging_buffer);
  ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
  *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer);
  *end = GPR_SLICE_END_PTR(ep->write_staging_buffer);
}
Example #8
0
grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
    void *parser, grpc_chttp2_parse_state *state, gpr_slice slice,
    int is_last) {
  gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice);
  gpr_uint8 *const end = GPR_SLICE_END_PTR(slice);
  gpr_uint8 *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) {
      state->process_ping_reply = 1;
    } else {
      state->send_ping_ack = 1;
    }
  }

  return GRPC_CHTTP2_PARSE_OK;
}
Example #9
0
gpr_slice gpr_permissive_percent_decode_slice(gpr_slice slice_in) {
  const uint8_t *p = GPR_SLICE_START_PTR(slice_in);
  const uint8_t *in_end = GPR_SLICE_END_PTR(slice_in);
  size_t out_length = 0;
  bool any_percent_encoded_stuff = false;
  while (p != in_end) {
    if (*p == '%') {
      if (!valid_hex(p + 1, in_end) || !valid_hex(p + 2, in_end)) {
        p++;
        out_length++;
      } else {
        p += 3;
        out_length++;
        any_percent_encoded_stuff = true;
      }
    } else {
      p++;
      out_length++;
    }
  }
  if (!any_percent_encoded_stuff) {
    return gpr_slice_ref(slice_in);
  }
  p = GPR_SLICE_START_PTR(slice_in);
  gpr_slice out = gpr_slice_malloc(out_length);
  uint8_t *q = GPR_SLICE_START_PTR(out);
  while (p != in_end) {
    if (*p == '%') {
      if (!valid_hex(p + 1, in_end) || !valid_hex(p + 2, in_end)) {
        *q++ = *p++;
      } else {
        *q++ = (uint8_t)(dehex(p[1]) << 4) | (dehex(p[2]));
        p += 3;
      }
    } else {
      *q++ = *p++;
    }
  }
  GPR_ASSERT(q == GPR_SLICE_END_PTR(out));
  return out;
}
Example #10
0
bool gpr_strict_percent_decode_slice(gpr_slice slice_in,
                                     const uint8_t *unreserved_bytes,
                                     gpr_slice *slice_out) {
  const uint8_t *p = GPR_SLICE_START_PTR(slice_in);
  const uint8_t *in_end = GPR_SLICE_END_PTR(slice_in);
  size_t out_length = 0;
  bool any_percent_encoded_stuff = false;
  while (p != in_end) {
    if (*p == '%') {
      if (!valid_hex(++p, in_end)) return false;
      if (!valid_hex(++p, in_end)) return false;
      p++;
      out_length++;
      any_percent_encoded_stuff = true;
    } else if (is_unreserved_character(*p, unreserved_bytes)) {
      p++;
      out_length++;
    } else {
      return false;
    }
  }
  if (!any_percent_encoded_stuff) {
    *slice_out = gpr_slice_ref(slice_in);
    return true;
  }
  p = GPR_SLICE_START_PTR(slice_in);
  *slice_out = gpr_slice_malloc(out_length);
  uint8_t *q = GPR_SLICE_START_PTR(*slice_out);
  while (p != in_end) {
    if (*p == '%') {
      *q++ = (uint8_t)(dehex(p[1]) << 4) | (dehex(p[2]));
      p += 3;
    } else {
      *q++ = *p++;
    }
  }
  GPR_ASSERT(q == GPR_SLICE_END_PTR(*slice_out));
  return true;
}
grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
    grpc_exec_ctx *exec_ctx, void *parser,
    grpc_chttp2_transport_parsing *transport_parsing,
    grpc_chttp2_stream_parsing *stream_parsing, 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_window_update_parser *p = parser;

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

  if (stream_parsing != NULL) {
    stream_parsing->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)) {
      gpr_log(GPR_ERROR, "invalid window update bytes: %d", p->amount);
      return GRPC_CHTTP2_CONNECTION_ERROR;
    }
    GPR_ASSERT(is_last);

    if (transport_parsing->incoming_stream_id != 0) {
      if (stream_parsing != NULL) {
        GRPC_CHTTP2_FLOW_CREDIT_STREAM("parse", transport_parsing,
                                       stream_parsing, outgoing_window,
                                       received_update);
        grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
                                                 stream_parsing);
      }
    } else {
      GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parse", transport_parsing,
                                        outgoing_window, received_update);
    }
  }

  return GRPC_CHTTP2_PARSE_OK;
}
Example #12
0
static void test_decode_random_headers_inner(int max_len) {
  int i;
  test_decode_random_header_state st;
  gpr_slice_buffer output;
  gpr_slice merged;
  grpc_stream_op_buffer encops;
  grpc_chttp2_hpack_parser parser;

  grpc_chttp2_hpack_parser_init(&parser, g_mdctx);
  grpc_sopb_init(&encops);

  gpr_log(GPR_INFO, "max_len = %d", max_len);

  for (i = 0; i < 10000; i++) {
    randstr(st.key, max_len);
    randstr(st.value, max_len);

    add_sopb_headers(1, st.key, st.value);
    gpr_slice_buffer_init(&output);
    GPR_ASSERT(0 ==
               grpc_chttp2_preencode(g_sopb.ops, &g_sopb.nops, 0, &encops));
    grpc_chttp2_encode(encops.ops, encops.nops, 0, 0xdeadbeef, &g_compressor,
                       &output);
    encops.nops = 0;
    merged = grpc_slice_merge(output.slices, output.count);
    gpr_slice_buffer_destroy(&output);

    st.got_hdr = 0;
    parser.on_header = chk_hdr;
    parser.on_header_user_data = &st;
    grpc_chttp2_hpack_parser_parse(&parser, GPR_SLICE_START_PTR(merged) + 9,
                                   GPR_SLICE_END_PTR(merged));
    GPR_ASSERT(st.got_hdr);

    gpr_slice_unref(merged);
  }

  grpc_chttp2_hpack_parser_destroy(&parser);
  grpc_sopb_destroy(&encops);
}
Example #13
0
void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code,
                               gpr_slice debug_data,
                               gpr_slice_buffer *slice_buffer) {
  gpr_slice header = gpr_slice_malloc(9 + 4 + 4);
  uint8_t *p = GPR_SLICE_START_PTR(header);
  uint32_t frame_length;
  GPR_ASSERT(GPR_SLICE_LENGTH(debug_data) < UINT32_MAX - 4 - 4);
  frame_length = 4 + 4 + (uint32_t)GPR_SLICE_LENGTH(debug_data);

  /* frame header: length */
  *p++ = (uint8_t)(frame_length >> 16);
  *p++ = (uint8_t)(frame_length >> 8);
  *p++ = (uint8_t)(frame_length);
  /* frame header: type */
  *p++ = GRPC_CHTTP2_FRAME_GOAWAY;
  /* frame header: flags */
  *p++ = 0;
  /* frame header: stream id */
  *p++ = 0;
  *p++ = 0;
  *p++ = 0;
  *p++ = 0;
  /* payload: last stream id */
  *p++ = (uint8_t)(last_stream_id >> 24);
  *p++ = (uint8_t)(last_stream_id >> 16);
  *p++ = (uint8_t)(last_stream_id >> 8);
  *p++ = (uint8_t)(last_stream_id);
  /* payload: error code */
  *p++ = (uint8_t)(error_code >> 24);
  *p++ = (uint8_t)(error_code >> 16);
  *p++ = (uint8_t)(error_code >> 8);
  *p++ = (uint8_t)(error_code);
  GPR_ASSERT(p == GPR_SLICE_END_PTR(header));
  gpr_slice_buffer_add(slice_buffer, header);
  gpr_slice_buffer_add(slice_buffer, debug_data);
}
Example #14
0
grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
    void *parser, grpc_chttp2_transport_parsing *transport_parsing,
    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
  gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice);
  gpr_uint8 *const end = GPR_SLICE_END_PTR(slice);
  gpr_uint8 *cur = beg;
  grpc_chttp2_data_parser *p = parser;
  gpr_uint32 message_flags = 0;

  if (is_last && p->is_last_frame) {
    stream_parsing->received_close = 1;
  }

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

  switch (p->state) {
  fh_0:
    case GRPC_CHTTP2_DATA_FH_0:
      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_log(GPR_ERROR, "Bad GRPC frame type 0x%02x", p->frame_type);
          return GRPC_CHTTP2_STREAM_ERROR;
      }
      if (++cur == end) {
        p->state = GRPC_CHTTP2_DATA_FH_1;
        return GRPC_CHTTP2_PARSE_OK;
      }
    /* fallthrough */
    case GRPC_CHTTP2_DATA_FH_1:
      p->frame_size = ((gpr_uint32)*cur) << 24;
      if (++cur == end) {
        p->state = GRPC_CHTTP2_DATA_FH_2;
        return GRPC_CHTTP2_PARSE_OK;
      }
    /* fallthrough */
    case GRPC_CHTTP2_DATA_FH_2:
      p->frame_size |= ((gpr_uint32)*cur) << 16;
      if (++cur == end) {
        p->state = GRPC_CHTTP2_DATA_FH_3;
        return GRPC_CHTTP2_PARSE_OK;
      }
    /* fallthrough */
    case GRPC_CHTTP2_DATA_FH_3:
      p->frame_size |= ((gpr_uint32)*cur) << 8;
      if (++cur == end) {
        p->state = GRPC_CHTTP2_DATA_FH_4;
        return GRPC_CHTTP2_PARSE_OK;
      }
    /* fallthrough */
    case GRPC_CHTTP2_DATA_FH_4:
      p->frame_size |= ((gpr_uint32)*cur);
      p->state = GRPC_CHTTP2_DATA_FRAME;
      ++cur;
      if (p->is_frame_compressed) {
        message_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
      }
      grpc_sopb_add_begin_message(&p->incoming_sopb, p->frame_size,
                                  message_flags);
    /* fallthrough */
    case GRPC_CHTTP2_DATA_FRAME:
      if (cur == end) {
        grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
                                                 stream_parsing);
        return GRPC_CHTTP2_PARSE_OK;
      }
      grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
                                               stream_parsing);
      if ((gpr_uint32)(end - cur) == p->frame_size) {
        grpc_sopb_add_slice(&p->incoming_sopb,
                            gpr_slice_sub(slice, cur - beg, end - beg));
        p->state = GRPC_CHTTP2_DATA_FH_0;
        return GRPC_CHTTP2_PARSE_OK;
      } else if ((gpr_uint32)(end - cur) > p->frame_size) {
        grpc_sopb_add_slice(
            &p->incoming_sopb,
            gpr_slice_sub(slice, cur - beg, cur + p->frame_size - beg));
        cur += p->frame_size;
        goto fh_0; /* loop */
      } else {
        grpc_sopb_add_slice(&p->incoming_sopb,
                            gpr_slice_sub(slice, cur - beg, end - beg));
        p->frame_size -= (end - cur);
        return GRPC_CHTTP2_PARSE_OK;
      }
  }

  gpr_log(GPR_ERROR, "should never reach here");
  abort();
  return GRPC_CHTTP2_CONNECTION_ERROR;
}
Example #15
0
static grpc_error *parse_inner(grpc_exec_ctx *exec_ctx,
                               grpc_chttp2_data_parser *p,
                               grpc_chttp2_transport *t, grpc_chttp2_stream *s,
                               gpr_slice slice) {
  uint8_t *const beg = GPR_SLICE_START_PTR(slice);
  uint8_t *const end = GPR_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 = gpr_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,
            gpr_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,
            gpr_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,
            gpr_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"));
}
Example #16
0
grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
    grpc_exec_ctx *exec_ctx, void *parser,
    grpc_chttp2_transport_parsing *transport_parsing,
    grpc_chttp2_stream_parsing *stream_parsing, 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_data_parser *p = parser;
  uint32_t message_flags;
  grpc_chttp2_incoming_byte_stream *incoming_byte_stream;

  if (is_last && p->is_last_frame) {
    stream_parsing->received_close = 1;
  }

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

  switch (p->state) {
  fh_0:
    case GRPC_CHTTP2_DATA_FH_0:
      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_log(GPR_ERROR, "Bad GRPC frame type 0x%02x", p->frame_type);
          return GRPC_CHTTP2_STREAM_ERROR;
      }
      if (++cur == end) {
        p->state = GRPC_CHTTP2_DATA_FH_1;
        return GRPC_CHTTP2_PARSE_OK;
      }
    /* fallthrough */
    case GRPC_CHTTP2_DATA_FH_1:
      p->frame_size = ((uint32_t)*cur) << 24;
      if (++cur == end) {
        p->state = GRPC_CHTTP2_DATA_FH_2;
        return GRPC_CHTTP2_PARSE_OK;
      }
    /* fallthrough */
    case GRPC_CHTTP2_DATA_FH_2:
      p->frame_size |= ((uint32_t)*cur) << 16;
      if (++cur == end) {
        p->state = GRPC_CHTTP2_DATA_FH_3;
        return GRPC_CHTTP2_PARSE_OK;
      }
    /* fallthrough */
    case GRPC_CHTTP2_DATA_FH_3:
      p->frame_size |= ((uint32_t)*cur) << 8;
      if (++cur == end) {
        p->state = GRPC_CHTTP2_DATA_FH_4;
        return GRPC_CHTTP2_PARSE_OK;
      }
    /* fallthrough */
    case GRPC_CHTTP2_DATA_FH_4:
      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, transport_parsing, stream_parsing, p->frame_size,
              message_flags, &p->incoming_frames);
    /* fallthrough */
    case GRPC_CHTTP2_DATA_FRAME:
      if (cur == end) {
        grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
                                                 stream_parsing);
        return GRPC_CHTTP2_PARSE_OK;
      }
      grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
                                               stream_parsing);
      if ((uint32_t)(end - cur) == p->frame_size) {
        grpc_chttp2_incoming_byte_stream_push(
            exec_ctx, p->parsing_frame,
            gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
        grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1,
                                                  1);
        p->parsing_frame = NULL;
        p->state = GRPC_CHTTP2_DATA_FH_0;
        return GRPC_CHTTP2_PARSE_OK;
      } else if ((uint32_t)(end - cur) > p->frame_size) {
        grpc_chttp2_incoming_byte_stream_push(
            exec_ctx, p->parsing_frame,
            gpr_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, 1,
                                                  1);
        p->parsing_frame = NULL;
        cur += p->frame_size;
        goto fh_0; /* loop */
      } else {
        grpc_chttp2_incoming_byte_stream_push(
            exec_ctx, p->parsing_frame,
            gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
        GPR_ASSERT((size_t)(end - cur) <= p->frame_size);
        p->frame_size -= (uint32_t)(end - cur);
        return GRPC_CHTTP2_PARSE_OK;
      }
  }

  GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR);
}
Example #17
0
static void close_from_api(grpc_chttp2_transport_global *transport_global,
                           grpc_chttp2_stream_global *stream_global,
                           grpc_status_code status,
                           gpr_slice *optional_message) {
  gpr_slice hdr;
  gpr_slice status_hdr;
  gpr_slice message_pfx;
  gpr_uint8 *p;
  gpr_uint32 len = 0;

  GPR_ASSERT(status >= 0 && (int)status < 100);

  stream_global->cancelled = 1;
  stream_global->cancelled_status = status;
  GPR_ASSERT(stream_global->id != 0);
  GPR_ASSERT(!stream_global->written_anything);

  /* Hand roll a header block.
     This is unnecessarily ugly - at some point we should find a more elegant
     solution.
     It's complicated by the fact that our send machinery would be dead by the
     time we got around to sending this, so instead we ignore HPACK compression
     and just write the uncompressed bytes onto the wire. */
  status_hdr = gpr_slice_malloc(15 + (status >= 10));
  p = GPR_SLICE_START_PTR(status_hdr);
  *p++ = 0x40; /* literal header */
  *p++ = 11;   /* len(grpc-status) */
  *p++ = 'g';
  *p++ = 'r';
  *p++ = 'p';
  *p++ = 'c';
  *p++ = '-';
  *p++ = 's';
  *p++ = 't';
  *p++ = 'a';
  *p++ = 't';
  *p++ = 'u';
  *p++ = 's';
  if (status < 10) {
    *p++ = 1;
    *p++ = (gpr_uint8)('0' + status);
  } else {
    *p++ = 2;
    *p++ = (gpr_uint8)('0' + (status / 10));
    *p++ = (gpr_uint8)('0' + (status % 10));
  }
  GPR_ASSERT(p == GPR_SLICE_END_PTR(status_hdr));
  len += (gpr_uint32)GPR_SLICE_LENGTH(status_hdr);

  if (optional_message) {
    GPR_ASSERT(GPR_SLICE_LENGTH(*optional_message) < 127);
    message_pfx = gpr_slice_malloc(15);
    p = GPR_SLICE_START_PTR(message_pfx);
    *p++ = 0x40;
    *p++ = 12; /* len(grpc-message) */
    *p++ = 'g';
    *p++ = 'r';
    *p++ = 'p';
    *p++ = 'c';
    *p++ = '-';
    *p++ = 'm';
    *p++ = 'e';
    *p++ = 's';
    *p++ = 's';
    *p++ = 'a';
    *p++ = 'g';
    *p++ = 'e';
    *p++ = (gpr_uint8)GPR_SLICE_LENGTH(*optional_message);
    GPR_ASSERT(p == GPR_SLICE_END_PTR(message_pfx));
    len += (gpr_uint32)GPR_SLICE_LENGTH(message_pfx);
    len += (gpr_uint32)GPR_SLICE_LENGTH(*optional_message);
  }

  hdr = gpr_slice_malloc(9);
  p = GPR_SLICE_START_PTR(hdr);
  *p++ = (gpr_uint8)(len >> 16);
  *p++ = (gpr_uint8)(len >> 8);
  *p++ = (gpr_uint8)(len);
  *p++ = GRPC_CHTTP2_FRAME_HEADER;
  *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS;
  *p++ = (gpr_uint8)(stream_global->id >> 24);
  *p++ = (gpr_uint8)(stream_global->id >> 16);
  *p++ = (gpr_uint8)(stream_global->id >> 8);
  *p++ = (gpr_uint8)(stream_global->id);
  GPR_ASSERT(p == GPR_SLICE_END_PTR(hdr));

  gpr_slice_buffer_add(&transport_global->qbuf, hdr);
  gpr_slice_buffer_add(&transport_global->qbuf, status_hdr);
  if (optional_message) {
    gpr_slice_buffer_add(&transport_global->qbuf, message_pfx);
    gpr_slice_buffer_add(&transport_global->qbuf,
                         gpr_slice_ref(*optional_message));
  }

  gpr_slice_buffer_add(
      &transport_global->qbuf,
      grpc_chttp2_rst_stream_create(stream_global->id, GRPC_CHTTP2_NO_ERROR));

  grpc_chttp2_list_add_read_write_state_changed(transport_global,
                                                stream_global);
}
Example #18
0
static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
                           gpr_slice_buffer *slices, grpc_closure *cb) {
  unsigned i;
  tsi_result result = TSI_OK;
  secure_endpoint *ep = (secure_endpoint *)secure_ep;
  uint8_t *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer);
  uint8_t *end = GPR_SLICE_END_PTR(ep->write_staging_buffer);

  gpr_slice_buffer_reset_and_unref(&ep->output_buffer);

  if (false && grpc_trace_secure_endpoint) {
    for (i = 0; i < slices->count; i++) {
      char *data =
          gpr_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++) {
    gpr_slice plain = slices->slices[i];
    uint8_t *message_bytes = GPR_SLICE_START_PTR(plain);
    size_t message_size = GPR_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 != GPR_SLICE_START_PTR(ep->write_staging_buffer)) {
      gpr_slice_buffer_add(
          &ep->output_buffer,
          gpr_slice_split_head(
              &ep->write_staging_buffer,
              (size_t)(cur - GPR_SLICE_START_PTR(ep->write_staging_buffer))));
    }
  }

  if (result != TSI_OK) {
    /* TODO(yangg) do different things according to the error type? */
    gpr_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);
    return;
  }

  grpc_endpoint_write(exec_ctx, ep->wrapped_ep, &ep->output_buffer, cb);
}
Example #19
0
int grpc_chttp2_perform_read(grpc_chttp2_transport_parsing *transport_parsing,
                             gpr_slice slice) {
    gpr_uint8 *beg = GPR_SLICE_START_PTR(slice);
    gpr_uint8 *end = GPR_SLICE_END_PTR(slice);
    gpr_uint8 *cur = beg;

    if (cur == end) return 1;

    switch (transport_parsing->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 && transport_parsing->deframe_state != GRPC_DTS_FH_0) {
            if (*cur != GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
                    ->deframe_state]) {
                gpr_log(GPR_INFO,
                        "Connect string mismatch: expected '%c' (%d) got '%c' (%d) "
                        "at byte %d",
                        GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
                                ->deframe_state],
                        (int)(gpr_uint8)GRPC_CHTTP2_CLIENT_CONNECT_STRING
                        [transport_parsing->deframe_state],
                        *cur, (int)*cur, transport_parsing->deframe_state);
                return 0;
            }
            ++cur;
            ++transport_parsing->deframe_state;
        }
        if (cur == end) {
            return 1;
        }
        /* fallthrough */
dts_fh_0:
    case GRPC_DTS_FH_0:
        GPR_ASSERT(cur < end);
        transport_parsing->incoming_frame_size = ((gpr_uint32)*cur) << 16;
        if (++cur == end) {
            transport_parsing->deframe_state = GRPC_DTS_FH_1;
            return 1;
        }
    /* fallthrough */
    case GRPC_DTS_FH_1:
        GPR_ASSERT(cur < end);
        transport_parsing->incoming_frame_size |= ((gpr_uint32)*cur) << 8;
        if (++cur == end) {
            transport_parsing->deframe_state = GRPC_DTS_FH_2;
            return 1;
        }
    /* fallthrough */
    case GRPC_DTS_FH_2:
        GPR_ASSERT(cur < end);
        transport_parsing->incoming_frame_size |= *cur;
        if (++cur == end) {
            transport_parsing->deframe_state = GRPC_DTS_FH_3;
            return 1;
        }
    /* fallthrough */
    case GRPC_DTS_FH_3:
        GPR_ASSERT(cur < end);
        transport_parsing->incoming_frame_type = *cur;
        if (++cur == end) {
            transport_parsing->deframe_state = GRPC_DTS_FH_4;
            return 1;
        }
    /* fallthrough */
    case GRPC_DTS_FH_4:
        GPR_ASSERT(cur < end);
        transport_parsing->incoming_frame_flags = *cur;
        if (++cur == end) {
            transport_parsing->deframe_state = GRPC_DTS_FH_5;
            return 1;
        }
    /* fallthrough */
    case GRPC_DTS_FH_5:
        GPR_ASSERT(cur < end);
        transport_parsing->incoming_stream_id = (((gpr_uint32)*cur) & 0x7f) << 24;
        if (++cur == end) {
            transport_parsing->deframe_state = GRPC_DTS_FH_6;
            return 1;
        }
    /* fallthrough */
    case GRPC_DTS_FH_6:
        GPR_ASSERT(cur < end);
        transport_parsing->incoming_stream_id |= ((gpr_uint32)*cur) << 16;
        if (++cur == end) {
            transport_parsing->deframe_state = GRPC_DTS_FH_7;
            return 1;
        }
    /* fallthrough */
    case GRPC_DTS_FH_7:
        GPR_ASSERT(cur < end);
        transport_parsing->incoming_stream_id |= ((gpr_uint32)*cur) << 8;
        if (++cur == end) {
            transport_parsing->deframe_state = GRPC_DTS_FH_8;
            return 1;
        }
    /* fallthrough */
    case GRPC_DTS_FH_8:
        GPR_ASSERT(cur < end);
        transport_parsing->incoming_stream_id |= ((gpr_uint32)*cur);
        transport_parsing->deframe_state = GRPC_DTS_FRAME;
        if (!init_frame_parser(transport_parsing)) {
            return 0;
        }
        if (transport_parsing->incoming_stream_id) {
            transport_parsing->last_incoming_stream_id =
                transport_parsing->incoming_stream_id;
        }
        if (transport_parsing->incoming_frame_size == 0) {
            if (!parse_frame_slice(transport_parsing, gpr_empty_slice(), 1)) {
                return 0;
            }
            transport_parsing->incoming_stream = NULL;
            if (++cur == end) {
                transport_parsing->deframe_state = GRPC_DTS_FH_0;
                return 1;
            }
            goto dts_fh_0; /* loop */
        }
        if (++cur == end) {
            return 1;
        }
    /* fallthrough */
    case GRPC_DTS_FRAME:
        GPR_ASSERT(cur < end);
        if ((gpr_uint32)(end - cur) == transport_parsing->incoming_frame_size) {
            if (!parse_frame_slice(
                        transport_parsing,
                        gpr_slice_sub_no_ref(slice, cur - beg, end - beg), 1)) {
                return 0;
            }
            transport_parsing->deframe_state = GRPC_DTS_FH_0;
            transport_parsing->incoming_stream = NULL;
            return 1;
        } else if ((gpr_uint32)(end - cur) >
                   transport_parsing->incoming_frame_size) {
            if (!parse_frame_slice(
                        transport_parsing,
                        gpr_slice_sub_no_ref(
                            slice, cur - beg,
                            cur + transport_parsing->incoming_frame_size - beg),
                        1)) {
                return 0;
            }
            cur += transport_parsing->incoming_frame_size;
            transport_parsing->incoming_stream = NULL;
            goto dts_fh_0; /* loop */
        } else {
            if (!parse_frame_slice(
                        transport_parsing,
                        gpr_slice_sub_no_ref(slice, cur - beg, end - beg), 0)) {
                return 0;
            }
            transport_parsing->incoming_frame_size -= (end - cur);
            return 1;
        }
        gpr_log(GPR_ERROR, "should never reach here");
        abort();
    }

    gpr_log(GPR_ERROR, "should never reach here");
    abort();

    return 0;
}
Example #20
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 = GPR_SLICE_START_PTR(ep->read_staging_buffer);
  uint8_t *end = GPR_SLICE_END_PTR(ep->read_staging_buffer);

  if (error != GRPC_ERROR_NONE) {
    gpr_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++) {
    gpr_slice encrypted = ep->source_buffer.slices[i];
    uint8_t *message_bytes = GPR_SLICE_START_PTR(encrypted);
    size_t message_size = GPR_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 != GPR_SLICE_START_PTR(ep->read_staging_buffer)) {
    gpr_slice_buffer_add(
        ep->read_buffer,
        gpr_slice_split_head(
            &ep->read_staging_buffer,
            (size_t)(cur - GPR_SLICE_START_PTR(ep->read_staging_buffer))));
  }

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

  if (result != TSI_OK) {
    gpr_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);
}
grpc_error *grpc_chttp2_perform_read(
    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
    gpr_slice slice) {
  uint8_t *beg = GPR_SLICE_START_PTR(slice);
  uint8_t *end = GPR_SLICE_END_PTR(slice);
  uint8_t *cur = beg;
  grpc_error *err;

  if (cur == end) return GRPC_ERROR_NONE;

  switch (transport_parsing->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 && transport_parsing->deframe_state != GRPC_DTS_FH_0) {
        if (*cur != GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
                                                          ->deframe_state]) {
          char *msg;
          gpr_asprintf(
              &msg,
              "Connect string mismatch: expected '%c' (%d) got '%c' (%d) "
              "at byte %d",
              GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
                                                    ->deframe_state],
              (int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING
                  [transport_parsing->deframe_state],
              *cur, (int)*cur, transport_parsing->deframe_state);
          err = GRPC_ERROR_CREATE(msg);
          gpr_free(msg);
          return err;
        }
        ++cur;
        ++transport_parsing->deframe_state;
      }
      if (cur == end) {
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    dts_fh_0:
    case GRPC_DTS_FH_0:
      GPR_ASSERT(cur < end);
      transport_parsing->incoming_frame_size = ((uint32_t)*cur) << 16;
      if (++cur == end) {
        transport_parsing->deframe_state = GRPC_DTS_FH_1;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_DTS_FH_1:
      GPR_ASSERT(cur < end);
      transport_parsing->incoming_frame_size |= ((uint32_t)*cur) << 8;
      if (++cur == end) {
        transport_parsing->deframe_state = GRPC_DTS_FH_2;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_DTS_FH_2:
      GPR_ASSERT(cur < end);
      transport_parsing->incoming_frame_size |= *cur;
      if (++cur == end) {
        transport_parsing->deframe_state = GRPC_DTS_FH_3;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_DTS_FH_3:
      GPR_ASSERT(cur < end);
      transport_parsing->incoming_frame_type = *cur;
      if (++cur == end) {
        transport_parsing->deframe_state = GRPC_DTS_FH_4;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_DTS_FH_4:
      GPR_ASSERT(cur < end);
      transport_parsing->incoming_frame_flags = *cur;
      if (++cur == end) {
        transport_parsing->deframe_state = GRPC_DTS_FH_5;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_DTS_FH_5:
      GPR_ASSERT(cur < end);
      transport_parsing->incoming_stream_id = (((uint32_t)*cur) & 0x7f) << 24;
      if (++cur == end) {
        transport_parsing->deframe_state = GRPC_DTS_FH_6;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_DTS_FH_6:
      GPR_ASSERT(cur < end);
      transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 16;
      if (++cur == end) {
        transport_parsing->deframe_state = GRPC_DTS_FH_7;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_DTS_FH_7:
      GPR_ASSERT(cur < end);
      transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 8;
      if (++cur == end) {
        transport_parsing->deframe_state = GRPC_DTS_FH_8;
        return GRPC_ERROR_NONE;
      }
    /* fallthrough */
    case GRPC_DTS_FH_8:
      GPR_ASSERT(cur < end);
      transport_parsing->incoming_stream_id |= ((uint32_t)*cur);
      transport_parsing->deframe_state = GRPC_DTS_FRAME;
      err = init_frame_parser(exec_ctx, transport_parsing);
      if (err != GRPC_ERROR_NONE) {
        return err;
      }
      if (transport_parsing->incoming_stream_id != 0 &&
          transport_parsing->incoming_stream_id >
              transport_parsing->last_incoming_stream_id) {
        transport_parsing->last_incoming_stream_id =
            transport_parsing->incoming_stream_id;
      }
      if (transport_parsing->incoming_frame_size == 0) {
        err = parse_frame_slice(exec_ctx, transport_parsing, gpr_empty_slice(),
                                1);
        if (err != GRPC_ERROR_NONE) {
          return err;
        }
        transport_parsing->incoming_stream = NULL;
        if (++cur == end) {
          transport_parsing->deframe_state = GRPC_DTS_FH_0;
          return GRPC_ERROR_NONE;
        }
        goto dts_fh_0; /* loop */
      } else if (transport_parsing->incoming_frame_size >
                 transport_parsing->max_frame_size) {
        char *msg;
        gpr_asprintf(&msg, "Frame size %d is larger than max frame size %d",
                     transport_parsing->incoming_frame_size,
                     transport_parsing->max_frame_size);
        err = GRPC_ERROR_CREATE(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) == transport_parsing->incoming_frame_size) {
        err = parse_frame_slice(exec_ctx, transport_parsing,
                                gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
                                                     (size_t)(end - beg)),
                                1);
        if (err != GRPC_ERROR_NONE) {
          return err;
        }
        transport_parsing->deframe_state = GRPC_DTS_FH_0;
        transport_parsing->incoming_stream = NULL;
        return GRPC_ERROR_NONE;
      } else if ((uint32_t)(end - cur) >
                 transport_parsing->incoming_frame_size) {
        size_t cur_offset = (size_t)(cur - beg);
        err = parse_frame_slice(
            exec_ctx, transport_parsing,
            gpr_slice_sub_no_ref(
                slice, cur_offset,
                cur_offset + transport_parsing->incoming_frame_size),
            1);
        if (err != GRPC_ERROR_NONE) {
          return err;
        }
        cur += transport_parsing->incoming_frame_size;
        transport_parsing->incoming_stream = NULL;
        goto dts_fh_0; /* loop */
      } else {
        err = parse_frame_slice(exec_ctx, transport_parsing,
                                gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
                                                     (size_t)(end - beg)),
                                0);
        if (err != GRPC_ERROR_NONE) {
          return err;
        }
        transport_parsing->incoming_frame_size -= (uint32_t)(end - cur);
        return GRPC_ERROR_NONE;
      }
      GPR_UNREACHABLE_CODE(return 0);
  }

  GPR_UNREACHABLE_CODE(return 0);
}
Example #22
0
static void on_read(void *user_data, gpr_slice *slices, size_t nslices,
                    grpc_endpoint_cb_status error) {
  unsigned i;
  gpr_uint8 keep_looping = 0;
  size_t input_buffer_count = 0;
  tsi_result result = TSI_OK;
  secure_endpoint *ep = (secure_endpoint *)user_data;
  gpr_uint8 *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer);
  gpr_uint8 *end = GPR_SLICE_END_PTR(ep->read_staging_buffer);

  /* TODO(yangg) check error, maybe bail out early */
  for (i = 0; i < nslices; i++) {
    gpr_slice encrypted = slices[i];
    gpr_uint8 *message_bytes = GPR_SLICE_START_PTR(encrypted);
    size_t message_size = GPR_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 != GPR_SLICE_START_PTR(ep->read_staging_buffer)) {
    gpr_slice_buffer_add(
        &ep->input_buffer,
        gpr_slice_split_head(
            &ep->read_staging_buffer,
            (size_t)(cur - GPR_SLICE_START_PTR(ep->read_staging_buffer))));
  }

  /* TODO(yangg) experiment with moving this block after read_cb to see if it
     helps latency */
  for (i = 0; i < nslices; i++) {
    gpr_slice_unref(slices[i]);
  }

  if (result != TSI_OK) {
    gpr_slice_buffer_reset_and_unref(&ep->input_buffer);
    call_read_cb(ep, NULL, 0, GRPC_ENDPOINT_CB_ERROR);
    return;
  }
  /* The upper level will unref the slices. */
  input_buffer_count = ep->input_buffer.count;
  ep->input_buffer.count = 0;
  call_read_cb(ep, ep->input_buffer.slices, input_buffer_count, error);
}
Example #23
0
grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
    grpc_exec_ctx *exec_ctx, void *parser,
    grpc_chttp2_transport_parsing *transport_parsing,
    grpc_chttp2_stream_parsing *stream_parsing, 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_CHTTP2_PARSE_OK;
      }
      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_CHTTP2_PARSE_OK;
      }
      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_CHTTP2_PARSE_OK;
      }
      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_CHTTP2_PARSE_OK;
      }
      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_CHTTP2_PARSE_OK;
      }
      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_CHTTP2_PARSE_OK;
      }
      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_CHTTP2_PARSE_OK;
      }
      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_CHTTP2_PARSE_OK;
      }
      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) {
        transport_parsing->goaway_received = 1;
        transport_parsing->goaway_last_stream_index = p->last_stream_id;
        gpr_slice_unref(transport_parsing->goaway_text);
        transport_parsing->goaway_error = (grpc_status_code)p->error_code;
        transport_parsing->goaway_text =
            gpr_slice_new(p->debug_data, p->debug_length, gpr_free);
        p->debug_data = NULL;
      }
      return GRPC_CHTTP2_PARSE_OK;
  }
  GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR);
}
Example #24
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"));
}
Example #25
0
static grpc_endpoint_write_status endpoint_write(grpc_endpoint *secure_ep,
                                                 gpr_slice *slices,
                                                 size_t nslices,
                                                 grpc_endpoint_write_cb cb,
                                                 void *user_data) {
  unsigned i;
  size_t output_buffer_count = 0;
  tsi_result result = TSI_OK;
  secure_endpoint *ep = (secure_endpoint *)secure_ep;
  gpr_uint8 *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer);
  gpr_uint8 *end = GPR_SLICE_END_PTR(ep->write_staging_buffer);
  grpc_endpoint_write_status status;
  GPR_ASSERT(ep->output_buffer.count == 0);

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

  for (i = 0; i < nslices; i++) {
    gpr_slice plain = slices[i];
    gpr_uint8 *message_bytes = GPR_SLICE_START_PTR(plain);
    size_t message_size = GPR_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 != GPR_SLICE_START_PTR(ep->write_staging_buffer)) {
      gpr_slice_buffer_add(
          &ep->output_buffer,
          gpr_slice_split_head(
              &ep->write_staging_buffer,
              (size_t)(cur - GPR_SLICE_START_PTR(ep->write_staging_buffer))));
    }
  }

  for (i = 0; i < nslices; i++) {
    gpr_slice_unref(slices[i]);
  }

  if (result != TSI_OK) {
    /* TODO(yangg) do different things according to the error type? */
    gpr_slice_buffer_reset_and_unref(&ep->output_buffer);
    return GRPC_ENDPOINT_WRITE_ERROR;
  }

  /* clear output_buffer and let the lower level handle its slices. */
  output_buffer_count = ep->output_buffer.count;
  ep->output_buffer.count = 0;
  ep->write_cb = cb;
  ep->write_user_data = user_data;
  /* Need to keep the endpoint alive across a transport */
  secure_endpoint_ref(ep);
  status = grpc_endpoint_write(ep->wrapped_ep, ep->output_buffer.slices,
                               output_buffer_count, on_write, ep);
  if (status != GRPC_ENDPOINT_WRITE_PENDING) {
    secure_endpoint_unref(ep);
  }
  return status;
}