| 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(); | 
| } | 
|  | 
| //------------------------------------------------------------------------------ | 
|  |