diff options
author | dmichael@chromium.org <dmichael@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-10 17:26:03 +0000 |
---|---|---|
committer | dmichael@chromium.org <dmichael@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-10 17:26:03 +0000 |
commit | ff79fa2e4ed182580ccdea61ba24a955f8f06507 (patch) | |
tree | f725cd487192caa355ddef4ed0ef39f3db955a04 /ipc | |
parent | 4575961728be1794ed1f58f5210368d633d20590 (diff) | |
download | chromium_src-ff79fa2e4ed182580ccdea61ba24a955f8f06507.zip chromium_src-ff79fa2e4ed182580ccdea61ba24a955f8f06507.tar.gz chromium_src-ff79fa2e4ed182580ccdea61ba24a955f8f06507.tar.bz2 |
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
Diffstat (limited to 'ipc')
-rw-r--r-- | ipc/ipc_channel_nacl.cc | 90 | ||||
-rw-r--r-- | ipc/ipc_channel_nacl.h | 19 |
2 files changed, 76 insertions, 33 deletions
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<char> data; + std::vector<int> fds; +}; + namespace { -scoped_ptr<std::vector<char> > ReadDataOnReaderThread(int pipe) { +bool ReadDataOnReaderThread(int pipe, MessageContents* contents) { DCHECK(pipe >= 0); - if (pipe < 0) - return scoped_ptr<std::vector<char> >(); + return false; + + contents->data.resize(Channel::kReadBufferSize); + contents->fds.resize(FileDescriptorSet::kMaxDescriptorsPerMessage); - scoped_ptr<std::vector<char> > buffer( - new std::vector<char>(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<std::vector<char> >(); + 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<void (scoped_ptr<std::vector<char> >)> data_read_callback, + base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback, base::Callback<void ()> failure_callback, - base::MessageLoopProxy* main_message_loop); + scoped_refptr<base::MessageLoopProxy> 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<void (scoped_ptr<std::vector<char> >)> data_read_callback_; + base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback_; base::Callback<void ()> failure_callback_; scoped_refptr<base::MessageLoopProxy> main_message_loop_; @@ -85,9 +92,9 @@ class Channel::ChannelImpl::ReaderThreadRunner Channel::ChannelImpl::ReaderThreadRunner::ReaderThreadRunner( int pipe, - base::Callback<void (scoped_ptr<std::vector<char> >)> data_read_callback, + base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback, base::Callback<void ()> failure_callback, - base::MessageLoopProxy* main_message_loop) + scoped_refptr<base::MessageLoopProxy> 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<std::vector<char> > buffer(ReadDataOnReaderThread(pipe_)); - if (buffer.get()) { + scoped_ptr<MessageContents> 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<std::vector<char> > buffer) { +void Channel::ChannelImpl::DidRecvMsg(scoped_ptr<MessageContents> 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<std::vector<char> >(buffer.release())); + linked_ptr<std::vector<char> > data(new std::vector<char>); + 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<Message> msg = output_queue_.front(); output_queue_.pop_front(); - struct NaClImcMsgHdr msgh = {0}; - struct NaClImcMsgIoVec iov = {const_cast<void*>(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<void*>(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<std::vector<char> > buffer); + void DidRecvMsg(scoped_ptr<MessageContents> 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<linked_ptr<std::vector<char> > > 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<int> 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. |