static void tcp_handle_write(void *arg /* grpc_tcp */, int success) {
  grpc_tcp *tcp = (grpc_tcp *)arg;
  grpc_endpoint_op_status status;
  grpc_iomgr_closure *cb;

  if (!success) {
    cb = tcp->write_cb;
    tcp->write_cb = NULL;
    cb->cb(cb->cb_arg, 0);
    TCP_UNREF(tcp, "write");
    return;
  }

  GRPC_TIMER_BEGIN(GRPC_PTAG_TCP_CB_WRITE, 0);
  status = tcp_flush(tcp);
  if (status == GRPC_ENDPOINT_PENDING) {
    grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_closure);
  } else {
    cb = tcp->write_cb;
    tcp->write_cb = NULL;
    cb->cb(cb->cb_arg, status == GRPC_ENDPOINT_DONE);
    TCP_UNREF(tcp, "write");
  }
  GRPC_TIMER_END(GRPC_PTAG_TCP_CB_WRITE, 0);
}
Exemple #2
0
static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
                             int success) {
  grpc_tcp *tcp = (grpc_tcp *)arg;
  flush_result status;
  grpc_closure *cb;

  if (!success) {
    cb = tcp->write_cb;
    tcp->write_cb = NULL;
    cb->cb(exec_ctx, cb->cb_arg, 0);
    TCP_UNREF(exec_ctx, tcp, "write");
    return;
  }

  GRPC_TIMER_BEGIN(GRPC_PTAG_TCP_CB_WRITE, 0);
  status = tcp_flush(tcp);
  if (status == FLUSH_PENDING) {
    grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure);
  } else {
    cb = tcp->write_cb;
    tcp->write_cb = NULL;
    cb->cb(exec_ctx, cb->cb_arg, status == FLUSH_DONE);
    TCP_UNREF(exec_ctx, tcp, "write");
  }
  GRPC_TIMER_END(GRPC_PTAG_TCP_CB_WRITE, 0);
}
Exemple #3
0
static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
                      gpr_slice_buffer *buf, grpc_closure *cb) {
  grpc_tcp *tcp = (grpc_tcp *)ep;
  flush_result status;

  if (grpc_tcp_trace) {
    size_t i;

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

  GRPC_TIMER_BEGIN(GRPC_PTAG_TCP_WRITE, 0);
  GPR_ASSERT(tcp->write_cb == NULL);

  if (buf->length == 0) {
    GRPC_TIMER_END(GRPC_PTAG_TCP_WRITE, 0);
    grpc_exec_ctx_enqueue(exec_ctx, cb, 1);
    return;
  }
  tcp->outgoing_buffer = buf;
  tcp->outgoing_slice_idx = 0;
  tcp->outgoing_byte_idx = 0;

  status = tcp_flush(tcp);
  if (status == FLUSH_PENDING) {
    TCP_REF(tcp, "write");
    tcp->write_cb = cb;
    grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure);
  } else {
    grpc_exec_ctx_enqueue(exec_ctx, cb, status == FLUSH_DONE);
  }

  GRPC_TIMER_END(GRPC_PTAG_TCP_WRITE, 0);
}
static grpc_endpoint_op_status tcp_write(grpc_endpoint *ep,
                                         gpr_slice_buffer *buf,
                                         grpc_iomgr_closure *cb) {
  grpc_tcp *tcp = (grpc_tcp *)ep;
  grpc_endpoint_op_status status;

  if (grpc_tcp_trace) {
    size_t i;

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

  GRPC_TIMER_BEGIN(GRPC_PTAG_TCP_WRITE, 0);
  GPR_ASSERT(tcp->write_cb == NULL);

  if (buf->length == 0) {
    GRPC_TIMER_END(GRPC_PTAG_TCP_WRITE, 0);
    return GRPC_ENDPOINT_DONE;
  }
  tcp->outgoing_buffer = buf;
  tcp->outgoing_slice_idx = 0;
  tcp->outgoing_byte_idx = 0;

  status = tcp_flush(tcp);
  if (status == GRPC_ENDPOINT_PENDING) {
    TCP_REF(tcp, "write");
    tcp->write_cb = cb;
    grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_closure);
  }

  GRPC_TIMER_END(GRPC_PTAG_TCP_WRITE, 0);
  return status;
}
static grpc_endpoint_op_status tcp_flush(grpc_tcp *tcp) {
  struct msghdr msg;
  struct iovec iov[MAX_WRITE_IOVEC];
  int iov_size;
  ssize_t sent_length;
  ssize_t sending_length;
  ssize_t trailing;
  ssize_t unwind_slice_idx;
  ssize_t unwind_byte_idx;

  for (;;) {
    sending_length = 0;
    unwind_slice_idx = tcp->outgoing_slice_idx;
    unwind_byte_idx = tcp->outgoing_byte_idx;
    for (iov_size = 0; tcp->outgoing_slice_idx != tcp->outgoing_buffer->count &&
                       iov_size != MAX_WRITE_IOVEC;
         iov_size++) {
      iov[iov_size].iov_base =
          GPR_SLICE_START_PTR(
              tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) +
          tcp->outgoing_byte_idx;
      iov[iov_size].iov_len =
          GPR_SLICE_LENGTH(
              tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) -
          tcp->outgoing_byte_idx;
      sending_length += iov[iov_size].iov_len;
      tcp->outgoing_slice_idx++;
      tcp->outgoing_byte_idx = 0;
    }
    GPR_ASSERT(iov_size > 0);

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

    GRPC_TIMER_BEGIN(GRPC_PTAG_SENDMSG, 0);
    do {
      /* TODO(klempner): Cork if this is a partial write */
      sent_length = sendmsg(tcp->fd, &msg, SENDMSG_FLAGS);
    } while (sent_length < 0 && errno == EINTR);
    GRPC_TIMER_END(GRPC_PTAG_SENDMSG, 0);

    if (sent_length < 0) {
      if (errno == EAGAIN) {
        tcp->outgoing_slice_idx = unwind_slice_idx;
        tcp->outgoing_byte_idx = unwind_byte_idx;
        return GRPC_ENDPOINT_PENDING;
      } else {
        /* TODO(klempner): Log some of these */
        return GRPC_ENDPOINT_ERROR;
      }
    }

    GPR_ASSERT(tcp->outgoing_byte_idx == 0);
    trailing = sending_length - sent_length;
    while (trailing > 0) {
      ssize_t slice_length;

      tcp->outgoing_slice_idx--;
      slice_length = GPR_SLICE_LENGTH(
          tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]);
      if (slice_length > trailing) {
        tcp->outgoing_byte_idx = slice_length - trailing;
        break;
      } else {
        trailing -= slice_length;
      }
    }

    if (tcp->outgoing_slice_idx == tcp->outgoing_buffer->count) {
      return GRPC_ENDPOINT_DONE;
    }
  };
}
static void tcp_continue_read(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);
  GRPC_TIMER_BEGIN(GRPC_PTAG_HANDLE_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;

  GRPC_TIMER_BEGIN(GRPC_PTAG_RECVMSG, 0);
  do {
    read_bytes = recvmsg(tcp->fd, &msg, 0);
  } while (read_bytes < 0 && errno == EINTR);
  GRPC_TIMER_END(GRPC_PTAG_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(tcp->em_fd, &tcp->read_closure);
    } else {
      /* TODO(klempner): Log interesting errors */
      gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
      call_read_cb(tcp, 0);
      TCP_UNREF(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(tcp, 0);
    TCP_UNREF(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 - read_bytes);
    } else if (tcp->iov_size < MAX_READ_IOVEC) {
      ++tcp->iov_size;
    }
    GPR_ASSERT((size_t)read_bytes == tcp->incoming_buffer->length);
    call_read_cb(tcp, 1);
    TCP_UNREF(tcp, "read");
  }

  GRPC_TIMER_END(GRPC_PTAG_HANDLE_READ, 0);
}