Ejemplo n.º 1
0
static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
  struct msghdr msg;
  struct iovec iov[MAX_READ_IOVEC];
  ssize_t read_bytes;
  size_t i;

  GPR_ASSERT(!tcp->finished_edge);
  GPR_ASSERT(tcp->iov_size <= MAX_READ_IOVEC);
  GPR_ASSERT(tcp->incoming_buffer->count <= MAX_READ_IOVEC);
  GPR_TIMER_BEGIN("tcp_continue_read", 0);

  while (tcp->incoming_buffer->count < (size_t)tcp->iov_size) {
    gpr_slice_buffer_add_indexed(tcp->incoming_buffer,
                                 gpr_slice_malloc(tcp->slice_size));
  }
  for (i = 0; i < tcp->incoming_buffer->count; i++) {
    iov[i].iov_base = GPR_SLICE_START_PTR(tcp->incoming_buffer->slices[i]);
    iov[i].iov_len = GPR_SLICE_LENGTH(tcp->incoming_buffer->slices[i]);
  }

  msg.msg_name = NULL;
  msg.msg_namelen = 0;
  msg.msg_iov = iov;
  msg.msg_iovlen = tcp->iov_size;
  msg.msg_control = NULL;
  msg.msg_controllen = 0;
  msg.msg_flags = 0;

  GPR_TIMER_BEGIN("recvmsg", 1);
  do {
    read_bytes = recvmsg(tcp->fd, &msg, 0);
  } while (read_bytes < 0 && errno == EINTR);
  GPR_TIMER_END("recvmsg", 0);

  if (read_bytes < 0) {
    /* NB: After calling call_read_cb a parallel call of the read handler may
     * be running. */
    if (errno == EAGAIN) {
      if (tcp->iov_size > 1) {
        tcp->iov_size /= 2;
      }
      /* We've consumed the edge, request a new one */
      grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure);
    } else {
      /* TODO(klempner): Log interesting errors */
      gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
      call_read_cb(exec_ctx, tcp, 0);
      TCP_UNREF(exec_ctx, tcp, "read");
    }
  } else if (read_bytes == 0) {
    /* 0 read size ==> end of stream */
    gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
    call_read_cb(exec_ctx, tcp, 0);
    TCP_UNREF(exec_ctx, tcp, "read");
  } else {
    GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length);
    if ((size_t)read_bytes < tcp->incoming_buffer->length) {
      gpr_slice_buffer_trim_end(
          tcp->incoming_buffer,
          tcp->incoming_buffer->length - (size_t)read_bytes,
          &tcp->last_read_buffer);
    } else if (tcp->iov_size < MAX_READ_IOVEC) {
      ++tcp->iov_size;
    }
    GPR_ASSERT((size_t)read_bytes == tcp->incoming_buffer->length);
    call_read_cb(exec_ctx, tcp, 1);
    TCP_UNREF(exec_ctx, tcp, "read");
  }

  GPR_TIMER_END("tcp_continue_read", 0);
}
Ejemplo n.º 2
0
int grpc_chttp2_unlocking_check_writes(
    grpc_chttp2_transport_global *transport_global,
    grpc_chttp2_transport_writing *transport_writing, int is_parsing) {
  grpc_chttp2_stream_global *stream_global;
  grpc_chttp2_stream_writing *stream_writing;

  GPR_TIMER_BEGIN("grpc_chttp2_unlocking_check_writes", 0);

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

  grpc_chttp2_hpack_compressor_set_max_table_size(
      &transport_writing->hpack_compressor,
      transport_global->settings[GRPC_PEER_SETTINGS]
                                [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);

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

  GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window,
                                  transport_global, outgoing_window);

  /* for each grpc_chttp2_stream that's become writable, frame it's data
     (according to available window sizes) and add to the output buffer */
  while (grpc_chttp2_list_pop_writable_stream(
      transport_global, transport_writing, &stream_global, &stream_writing)) {
    gpr_uint8 sent_initial_metadata;

    stream_writing->id = stream_global->id;
    stream_writing->read_closed = stream_global->read_closed;

    GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_writing, stream_writing,
                                 outgoing_window, stream_global,
                                 outgoing_window);

    sent_initial_metadata = stream_writing->sent_initial_metadata;
    if (!sent_initial_metadata && stream_global->send_initial_metadata) {
      stream_writing->send_initial_metadata =
          stream_global->send_initial_metadata;
      stream_global->send_initial_metadata = NULL;
      if (grpc_chttp2_list_add_writing_stream(transport_writing,
                                              stream_writing)) {
        GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
      }
      sent_initial_metadata = 1;
    }
    if (sent_initial_metadata) {
      if (stream_global->send_message != NULL) {
        gpr_slice hdr = gpr_slice_malloc(5);
        gpr_uint8 *p = GPR_SLICE_START_PTR(hdr);
        gpr_uint32 len = stream_global->send_message->length;
        GPR_ASSERT(stream_writing->send_message == NULL);
        p[0] = (stream_global->send_message->flags &
                GRPC_WRITE_INTERNAL_COMPRESS) != 0;
        p[1] = (gpr_uint8)(len >> 24);
        p[2] = (gpr_uint8)(len >> 16);
        p[3] = (gpr_uint8)(len >> 8);
        p[4] = (gpr_uint8)(len);
        gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer, hdr);
        if (stream_global->send_message->length > 0) {
          stream_writing->send_message = stream_global->send_message;
        } else {
          stream_writing->send_message = NULL;
        }
        stream_writing->stream_fetched = 0;
        stream_global->send_message = NULL;
      }
      if ((stream_writing->send_message != NULL ||
           stream_writing->flow_controlled_buffer.length > 0) &&
          stream_writing->outgoing_window > 0) {
        if (transport_writing->outgoing_window > 0) {
          if (grpc_chttp2_list_add_writing_stream(transport_writing,
                                                  stream_writing)) {
            GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
          }
        } else {
          grpc_chttp2_list_add_stalled_by_transport(transport_writing,
                                                    stream_writing);
        }
      }
      if (stream_global->send_trailing_metadata) {
        stream_writing->send_trailing_metadata =
            stream_global->send_trailing_metadata;
        stream_global->send_trailing_metadata = NULL;
        if (grpc_chttp2_list_add_writing_stream(transport_writing,
                                                stream_writing)) {
          GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
        }
      }
    }

    if (!stream_global->read_closed &&
        stream_global->unannounced_incoming_window_for_writing > 1024) {
      GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_global, stream_writing,
                                   announce_window, stream_global,
                                   unannounced_incoming_window_for_writing);
      if (grpc_chttp2_list_add_writing_stream(transport_writing,
                                              stream_writing)) {
        GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
      }
    }
  }
Ejemplo n.º 3
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);
}
Ejemplo n.º 4
0
static gpr_slice large_slice(void) {
  gpr_slice slice = gpr_slice_malloc(1000000);
  memset(GPR_SLICE_START_PTR(slice), 'x', GPR_SLICE_LENGTH(slice));
  return slice;
}
Ejemplo n.º 5
0
gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t length) {
  gpr_slice slice = gpr_slice_malloc(length);
  memcpy(GPR_SLICE_START_PTR(slice), source, length);
  return slice;
}