예제 #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);
}
예제 #2
0
파일: writing.c 프로젝트: robottomw/grpc
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");
      }
    }
  }
예제 #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);
}
예제 #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;
}
예제 #5
0
파일: slice.c 프로젝트: kdavison/grpc
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;
}