From ff79fa2e4ed182580ccdea61ba24a955f8f06507 Mon Sep 17 00:00:00 2001 From: "dmichael@chromium.org" Date: Tue, 10 Jul 2012 17:26:03 +0000 Subject: PPAPI/NaCl: Support Handle passing in ipc_channel_nacl This is speculative, since we don't have the underlying support in NaClIPCAdapter. But I verified locally that it works as well as it did before (i.e., sending data works). BUG=116317 TEST= Review URL: https://chromiumcodereview.appspot.com/10750005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@145899 0039d316-1c4b-4281-b951-d872f2087c98 --- ipc/ipc_channel_nacl.cc | 90 +++++++++++++++++++++++++++++++++---------------- ipc/ipc_channel_nacl.h | 19 ++++++++--- 2 files changed, 76 insertions(+), 33 deletions(-) (limited to 'ipc') diff --git a/ipc/ipc_channel_nacl.cc b/ipc/ipc_channel_nacl.cc index 47f895a..4dec85b 100644 --- a/ipc/ipc_channel_nacl.cc +++ b/ipc/ipc_channel_nacl.cc @@ -24,31 +24,39 @@ #include "ipc/ipc_logging.h" namespace IPC { + +struct MessageContents { + std::vector data; + std::vector fds; +}; + namespace { -scoped_ptr > ReadDataOnReaderThread(int pipe) { +bool ReadDataOnReaderThread(int pipe, MessageContents* contents) { DCHECK(pipe >= 0); - if (pipe < 0) - return scoped_ptr >(); + return false; + + contents->data.resize(Channel::kReadBufferSize); + contents->fds.resize(FileDescriptorSet::kMaxDescriptorsPerMessage); - scoped_ptr > buffer( - new std::vector(Channel::kReadBufferSize)); - struct NaClImcMsgHdr msg = {0}; - struct NaClImcMsgIoVec iov = {&buffer->at(0), buffer->size()}; - msg.iov = &iov; - msg.iov_length = 1; + NaClImcMsgIoVec iov = { &contents->data[0], contents->data.size() }; + NaClImcMsgHdr msg = { &iov, 1, &contents->fds[0], contents->fds.size() }; int bytes_read = imc_recvmsg(pipe, &msg, 0); if (bytes_read <= 0) { // NaClIPCAdapter::BlockingReceive returns -1 when the pipe closes (either // due to error or for regular shutdown). - return scoped_ptr >(); + contents->data.clear(); + contents->fds.clear(); + return false; } DCHECK(bytes_read); - buffer->resize(bytes_read); - return buffer.Pass(); + // Resize the buffers down to the number of bytes and fds we actually read. + contents->data.resize(bytes_read); + contents->fds.resize(msg.desc_length); + return true; } } // namespace @@ -58,17 +66,16 @@ class Channel::ChannelImpl::ReaderThreadRunner public: // |pipe|: A file descriptor from which we will read using imc_recvmsg. // |data_read_callback|: A callback we invoke (on the main thread) when we - // have read data. The callback is passed a buffer of - // data that was read. + // have read data. // |failure_callback|: A callback we invoke when we have a failure reading // from |pipe|. // |main_message_loop|: A proxy for the main thread, where we will invoke the // above callbacks. ReaderThreadRunner( int pipe, - base::Callback >)> data_read_callback, + base::Callback)> data_read_callback, base::Callback failure_callback, - base::MessageLoopProxy* main_message_loop); + scoped_refptr main_message_loop); // DelegateSimpleThread implementation. Reads data from the pipe in a loop // until either we are told to quit or a read fails. @@ -76,7 +83,7 @@ class Channel::ChannelImpl::ReaderThreadRunner private: int pipe_; - base::Callback >)> data_read_callback_; + base::Callback)> data_read_callback_; base::Callback failure_callback_; scoped_refptr main_message_loop_; @@ -85,9 +92,9 @@ class Channel::ChannelImpl::ReaderThreadRunner Channel::ChannelImpl::ReaderThreadRunner::ReaderThreadRunner( int pipe, - base::Callback >)> data_read_callback, + base::Callback)> data_read_callback, base::Callback failure_callback, - base::MessageLoopProxy* main_message_loop) + scoped_refptr main_message_loop) : pipe_(pipe), data_read_callback_(data_read_callback), failure_callback_(failure_callback), @@ -96,10 +103,11 @@ Channel::ChannelImpl::ReaderThreadRunner::ReaderThreadRunner( void Channel::ChannelImpl::ReaderThreadRunner::Run() { while (true) { - scoped_ptr > buffer(ReadDataOnReaderThread(pipe_)); - if (buffer.get()) { + scoped_ptr msg_contents(new MessageContents); + bool success = ReadDataOnReaderThread(pipe_, msg_contents.get()); + if (success) { main_message_loop_->PostTask(FROM_HERE, - base::Bind(data_read_callback_, base::Passed(buffer.Pass()))); + base::Bind(data_read_callback_, base::Passed(msg_contents.Pass()))); } else { main_message_loop_->PostTask(FROM_HERE, failure_callback_); // Because the read failed, we know we're going to quit. Don't bother @@ -187,13 +195,19 @@ bool Channel::ChannelImpl::Send(Message* message) { return true; } -void Channel::ChannelImpl::DidRecvMsg(scoped_ptr > buffer) { +void Channel::ChannelImpl::DidRecvMsg(scoped_ptr contents) { // Close sets the pipe to -1. It's possible we'll get a buffer sent to us from // the reader thread after Close is called. If so, we ignore it. if (pipe_ == -1) return; - read_queue_.push_back(linked_ptr >(buffer.release())); + linked_ptr > data(new std::vector); + data->swap(contents->data); + read_queue_.push_back(data); + + input_fds_.insert(input_fds_.end(), + contents->fds.begin(), contents->fds.end()); + contents->fds.clear(); // In POSIX, we would be told when there are bytes to read by implementing // OnFileCanReadWithoutBlocking in MessageLoopForIO::Watcher. In NaCl, we @@ -240,12 +254,16 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() { linked_ptr msg = output_queue_.front(); output_queue_.pop_front(); - struct NaClImcMsgHdr msgh = {0}; - struct NaClImcMsgIoVec iov = {const_cast(msg->data()), msg->size()}; - msgh.iov = &iov; - msgh.iov_length = 1; + int fds[FileDescriptorSet::kMaxDescriptorsPerMessage]; + const int num_fds = msg->file_descriptor_set()->size(); + DCHECK(num_fds <= FileDescriptorSet::kMaxDescriptorsPerMessage); + msg->file_descriptor_set()->GetDescriptors(fds); + + NaClImcMsgIoVec iov = { const_cast(msg->data()), msg->size() }; + NaClImcMsgHdr msgh = { &iov, 1, fds, num_fds }; ssize_t bytes_written = imc_sendmsg(pipe_, &msgh, 0); + DCHECK(bytes_written); // The trusted side shouldn't return 0. if (bytes_written < 0) { // The trusted side should only ever give us an error of EPIPE. We // should never be interrupted, nor should we get EAGAIN. @@ -256,6 +274,8 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() { << " Currently writing message of size: " << msg->size(); return false; + } else { + msg->file_descriptor_set()->CommitAll(); } // Message sent OK! @@ -297,11 +317,23 @@ Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData( } bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) { + uint16 header_fds = msg->header()->num_fds; + CHECK(header_fds == input_fds_.size()); + if (header_fds == 0) + return true; // Nothing to do. + + // The shenaniganery below with &foo.front() requires input_fds_ to have + // contiguous underlying storage (such as a simple array or a std::vector). + // This is why the header warns not to make input_fds_ a deque<>. + msg->file_descriptor_set()->SetDescriptors(&input_fds_.front(), + header_fds); + input_fds_.clear(); return true; } bool Channel::ChannelImpl::DidEmptyInputBuffers() { - return true; + // When the input data buffer is empty, the fds should be too. + return input_fds_.empty(); } void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) { diff --git a/ipc/ipc_channel_nacl.h b/ipc/ipc_channel_nacl.h index 84f4ef7..4fefe4f 100644 --- a/ipc/ipc_channel_nacl.h +++ b/ipc/ipc_channel_nacl.h @@ -19,6 +19,10 @@ namespace IPC { +// Contains the results from one call to imc_recvmsg (data and file +// descriptors). +struct MessageContents; + // Similar to the Posix version of ChannelImpl but for Native Client code. // This is somewhat different because sendmsg/recvmsg here do not follow POSIX // semantics. Instead, they are implemented by a custom embedding of @@ -42,7 +46,7 @@ class Channel::ChannelImpl : public internal::ChannelReader { bool Send(Message* message); // Posted to the main thread by ReaderThreadRunner. - void DidRecvMsg(scoped_ptr > buffer); + void DidRecvMsg(scoped_ptr contents); void ReadDidFail(); private: @@ -84,15 +88,22 @@ class Channel::ChannelImpl : public internal::ChannelReader { // IPC::ChannelReader expects to be able to call ReadData on us to // synchronously read data waiting in the pipe's buffer without blocking. // Since we can't do that (see 1 and 2 above), the reader thread does blocking - // reads and posts the data over to the main thread in byte vectors. Each byte - // vector is the result of one call to "recvmsg". When ReadData is called, it - // pulls the bytes out of these vectors in order. + // reads and posts the data over to the main thread in MessageContents. Each + // MessageContents object is the result of one call to "imc_recvmsg". + // DidRecvMsg breaks the MessageContents out in to the data and the file + // descriptors, and puts them on these two queues. // TODO(dmichael): There's probably a more efficient way to emulate this with // a circular buffer or something, so we don't have to do so // many heap allocations. But it maybe isn't worth // the trouble given that we probably want to implement 1 and // 2 above in NaCl eventually. + // When ReadData is called, it pulls the bytes out of this queue in order. std::deque > > read_queue_; + // Queue of file descriptors extracted from imc_recvmsg messages. + // NOTE: The implementation assumes underlying storage here is contiguous, so + // don't change to something like std::deque<> without changing the + // implementation! + std::vector input_fds_; // This queue is used when a message is sent prior to Connect having been // called. Normally after we're connected, the queue is empty. -- cgit v1.1