| Index: chrome/common/ipc_channel_posix.cc
|
| diff --git a/chrome/common/ipc_channel_posix.cc b/chrome/common/ipc_channel_posix.cc
|
| index a7bbb56ac019905a189c912cba48078f5206f5c8..bc77552f619e19dd4fba198abd328e40db4acfb0 100644
|
| --- a/chrome/common/ipc_channel_posix.cc
|
| +++ b/chrome/common/ipc_channel_posix.cc
|
| @@ -28,6 +28,7 @@
|
| #include "base/singleton.h"
|
| #include "chrome/common/chrome_counters.h"
|
| #include "chrome/common/chrome_switches.h"
|
| +#include "chrome/common/file_descriptor_posix.h"
|
| #include "chrome/common/ipc_message_utils.h"
|
|
|
| namespace IPC {
|
| @@ -357,16 +358,24 @@ bool Channel::ChannelImpl::Connect() {
|
| bool Channel::ChannelImpl::ProcessIncomingMessages() {
|
| ssize_t bytes_read = 0;
|
|
|
| + struct msghdr msg = {0};
|
| + struct iovec iov = {input_buf_, Channel::kReadBufferSize};
|
| +
|
| + msg.msg_iov = &iov;
|
| + msg.msg_iovlen = 1;
|
| + msg.msg_control = input_cmsg_buf_;
|
| + msg.msg_controllen = sizeof(input_cmsg_buf_);
|
| +
|
| for (;;) {
|
| if (bytes_read == 0) {
|
| if (pipe_ == -1)
|
| return false;
|
|
|
| // Read from pipe.
|
| - // recv() returns 0 if the connection has closed or EAGAIN if no data is
|
| - // waiting on the pipe.
|
| + // recvmsg() returns 0 if the connection has closed or EAGAIN if no data
|
| + // is waiting on the pipe.
|
| do {
|
| - bytes_read = read(pipe_, input_buf_, Channel::kReadBufferSize);
|
| + bytes_read = recvmsg(pipe_, &msg, MSG_DONTWAIT);
|
| } while (bytes_read == -1 && errno == EINTR);
|
|
|
| if (bytes_read < 0) {
|
| @@ -390,6 +399,33 @@ bool Channel::ChannelImpl::ProcessIncomingMessages() {
|
| client_pipe_ = -1;
|
| }
|
|
|
| + // a pointer to an array of |num_wire_fds| file descriptors from the read
|
| + const int* wire_fds;
|
| + unsigned num_wire_fds = 0;
|
| +
|
| + // walk the list of control messages and, if we find an array of file
|
| + // descriptors, save a pointer to the array
|
| + for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg;
|
| + cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
| + if (cmsg->cmsg_level == SOL_SOCKET &&
|
| + cmsg->cmsg_type == SCM_RIGHTS) {
|
| + const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
|
| + DCHECK(payload_len % sizeof(int) == 0);
|
| + wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
|
| + num_wire_fds = payload_len / 4;
|
| +
|
| + if (msg.msg_flags & MSG_CTRUNC) {
|
| + LOG(ERROR) << "SCM_RIGHTS message was truncated"
|
| + << " cmsg_len:" << cmsg->cmsg_len
|
| + << " fd:" << pipe_;
|
| + for (unsigned i = 0; i < num_wire_fds; ++i)
|
| + close(wire_fds[i]);
|
| + return false;
|
| + }
|
| + break;
|
| + }
|
| + }
|
| +
|
| // Process messages from input buffer.
|
| const char *p;
|
| const char *end;
|
| @@ -408,11 +444,50 @@ bool Channel::ChannelImpl::ProcessIncomingMessages() {
|
| end = p + input_overflow_buf_.size();
|
| }
|
|
|
| + // A pointer to an array of |num_fds| file descriptors which includes any
|
| + // fds that have spilled over from a previous read.
|
| + const int* fds;
|
| + unsigned num_fds;
|
| + unsigned fds_i = 0; // the index of the first unused descriptor
|
| +
|
| + if (input_overflow_fds_.empty()) {
|
| + fds = wire_fds;
|
| + num_fds = num_wire_fds;
|
| + } else {
|
| + const size_t prev_size = input_overflow_fds_.size();
|
| + input_overflow_fds_.resize(prev_size + num_wire_fds);
|
| + memcpy(&input_overflow_fds_[prev_size], wire_fds,
|
| + num_wire_fds * sizeof(int));
|
| + fds = &input_overflow_fds_[0];
|
| + num_fds = input_overflow_fds_.size();
|
| + }
|
| +
|
| while (p < end) {
|
| const char* message_tail = Message::FindNext(p, end);
|
| if (message_tail) {
|
| int len = static_cast<int>(message_tail - p);
|
| const Message m(p, len);
|
| + if (m.header()->num_fds) {
|
| + // the message has file descriptors
|
| + if (m.header()->num_fds > num_fds - fds_i) {
|
| + // the message has been completely received, but we didn't get
|
| + // enough file descriptors.
|
| + LOG(WARNING) << "Message needs unreceived descriptors"
|
| + << " channel:" << this
|
| + << " message-type:" << m.type()
|
| + << " header()->num_fds:" << m.header()->num_fds
|
| + << " num_fds:" << num_fds
|
| + << " fds_i:" << fds_i;
|
| + // close the existing file descriptors so that we don't leak them
|
| + for (unsigned i = fds_i; i < num_fds; ++i)
|
| + close(fds[i]);
|
| + input_overflow_fds_.clear();
|
| + return false;
|
| + }
|
| +
|
| + m.descriptor_set()->SetDescriptors(&fds[fds_i], m.header()->num_fds);
|
| + fds_i += m.header()->num_fds;
|
| + }
|
| #ifdef IPC_MESSAGE_DEBUG_EXTRA
|
| DLOG(INFO) << "received message on channel @" << this <<
|
| " with type " << m.type();
|
| @@ -431,6 +506,7 @@ bool Channel::ChannelImpl::ProcessIncomingMessages() {
|
| }
|
| }
|
| input_overflow_buf_.assign(p, end - p);
|
| + input_overflow_fds_ = std::vector<int>(&fds[fds_i], &fds[num_fds]);
|
|
|
| bytes_read = 0; // Get more data.
|
| }
|
| @@ -460,7 +536,37 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
|
| message_send_bytes_written_;
|
| ssize_t bytes_written = -1;
|
| do {
|
| - bytes_written = write(pipe_, out_bytes, amt_to_write);
|
| + struct msghdr msgh = {0};
|
| + struct iovec iov = {const_cast<char*>(out_bytes), amt_to_write};
|
| + msgh.msg_iov = &iov;
|
| + msgh.msg_iovlen = 1;
|
| + char buf[CMSG_SPACE(
|
| + sizeof(int[DescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE]))];
|
| +
|
| + if (message_send_bytes_written_ == 0 &&
|
| + !msg->descriptor_set()->empty()) {
|
| + // This is the first chunk of a message which has descriptors to send
|
| + struct cmsghdr *cmsg;
|
| + const unsigned num_fds = msg->descriptor_set()->size();
|
| +
|
| + DCHECK_LE(num_fds, DescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE);
|
| +
|
| + msgh.msg_control = buf;
|
| + msgh.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds);
|
| + cmsg = CMSG_FIRSTHDR(&msgh);
|
| + cmsg->cmsg_level = SOL_SOCKET;
|
| + cmsg->cmsg_type = SCM_RIGHTS;
|
| + cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds);
|
| + msg->descriptor_set()->GetDescriptors(
|
| + reinterpret_cast<int*>(CMSG_DATA(cmsg)));
|
| + msgh.msg_controllen = cmsg->cmsg_len;
|
| +
|
| + msg->header()->num_fds = num_fds;
|
| + }
|
| +
|
| + bytes_written = sendmsg(pipe_, &msgh, MSG_DONTWAIT);
|
| + if (bytes_written > 0)
|
| + msg->descriptor_set()->CommitAll();
|
| } while (bytes_written == -1 && errno == EINTR);
|
|
|
| if (bytes_written < 0 && errno != EAGAIN) {
|
| @@ -621,6 +727,13 @@ void Channel::ChannelImpl::Close() {
|
| output_queue_.pop();
|
| delete m;
|
| }
|
| +
|
| + // Close any outstanding, received file descriptors
|
| + for (std::vector<int>::iterator
|
| + i = input_overflow_fds_.begin(); i != input_overflow_fds_.end(); ++i) {
|
| + close(*i);
|
| + }
|
| + input_overflow_fds_.clear();
|
| }
|
|
|
| //------------------------------------------------------------------------------
|
|
|