Index: chrome/nacl/nacl_ipc_adapter.cc |
diff --git a/chrome/nacl/nacl_ipc_adapter.cc b/chrome/nacl/nacl_ipc_adapter.cc |
index 187eb8b602f85c4ffe4b4df23d48c3c84a2a8728..4d46a2d15d01192f2553fa76640160272ceeb754 100644 |
--- a/chrome/nacl/nacl_ipc_adapter.cc |
+++ b/chrome/nacl/nacl_ipc_adapter.cc |
@@ -129,6 +129,106 @@ void WriteFileDescriptor(IPC::Message* message, int index) { |
message->WriteInt(index); |
} |
+typedef std::vector<ppapi::proxy::SerializedSharedMemoryHandle> ShmHandles; |
+typedef std::vector<ppapi::proxy::SerializedFileDescriptor> FDs; |
+ |
+void ExtractHandle(const ppapi::proxy::SerializedSharedMemoryHandle& handle, |
+ ShmHandles* handles, FDs* /* fds */, IPC::Message* msg, |
+ int* index) { |
+ handles->push_back(handle); |
+ if (msg) |
+ WriteFileDescriptor(msg, (*index)++); |
+} |
+void ExtractHandle(const ppapi::proxy::SerializedFileDescriptor& fd, |
+ ShmHandles* /* handles */, FDs* fds, IPC::Message* msg, |
+ int* index) { |
+ fds->push_back(fd); |
+ if (msg) |
+ WriteFileDescriptor(msg, (*index)++); |
+} |
+template <class T> |
+ExtractHandle(cont T& param, ShmHandles* /* handles */, FDs* /* fds */, |
+ IPC::Message* msg, int* index) { |
+ // It's not a handle, so just write to the output message, if necessary. |
+ if (msg) |
+ IPC::WriteParam(m, param); |
+} |
+ |
+// These just break apart the given tuple and run ExtractHandle over each param. |
+// The idea is to extract any handles in the tuple, while writing all data to |
+// msg (if msg is valid). The msg will only be valid on Windows, where we need |
+// to re-write the message to include the handles in POSIX style for NaCl. |
+template <class A> |
+void ExtractHandlesImpl(const Tuple1<A>& t1, ShmHandles* handles, FDs* fds, |
+ IPC::Message* msg) { |
+ int fd_index = 0; |
+ ExtractHandle(t1.a, handles, fds, msg, &fd_index); |
+} |
+template <class A, class B> |
+void ExtractHandlesImpl(const Tuple2<A, B>& t1, ShmHandles* handles, FDs* fds, |
+ IPC::Message* msg) { |
+ int fd_index = 0; |
+ ExtractHandle(t1.a, handles, fds, msg, &fd_index); |
+ ExtractHandle(t1.b, handles, fds, msg, &fd_index); |
+} |
+template <class A, class B, class C> |
+void ExtractHandlesImpl(const Tuple3<A, B, C>& t1, ShmHandles* handles, |
+ FDs* fds, IPC::Message* msg) { |
+ int fd_index = 0; |
+ ExtractHandle(t1.a, handles, fds, msg, &fd_index); |
+ ExtractHandle(t1.b, handles, fds, msg, &fd_index); |
+ ExtractHandle(t1.c, handles, fds, msg, &fd_index); |
+} |
+template <class A, class B, class C, class D> |
+void ExtractHandlesImpl(const Tuple4<A, B, C, D>& t1, ShmHandles* handles, |
+ FDs* fds, IPC::Message* msg) { |
+ int fd_index = 0; |
+ ExtractHandle(t1.a, handles, fds, msg, &fd_index); |
+ ExtractHandle(t1.b, handles, fds, msg, &fd_index); |
+ ExtractHandle(t1.c, handles, fds, msg, &fd_index); |
+ ExtractHandle(t1.d, handles, fds, msg, &fd_index); |
+} |
+template <class A, class B, class C, class D, class E> |
+void ExtractHandlesImpl(const Tuple5<A, B, C, D, E>& t1, ShmHandles* handles, |
+ FDs* fds, IPC::Message* msg) { |
+ int fd_index = 0; |
+ ExtractHandle(t1.a, handles, fds, msg, &fd_index); |
+ ExtractHandle(t1.b, handles, fds, msg, &fd_index); |
+ ExtractHandle(t1.c, handles, fds, msg, &fd_index); |
+ ExtractHandle(t1.d, handles, fds, msg, &fd_index); |
+ ExtractHandle(t1.e, handles, fds, msg, &fd_index); |
+} |
+template <class A, class B, class C, class D, class E, class F> |
+void ExtractHandlesImpl(const Tuple6<A, B, C, D, E, F>& t1, ShmHandles* handles, |
+ FDs* fds, IPC::Message* msg) { |
+ int fd_index = 0; |
+ ExtractHandle(t1.a, handles, fds, msg, &fd_index); |
+ ExtractHandle(t1.b, handles, fds, msg, &fd_index); |
+ ExtractHandle(t1.c, handles, fds, msg, &fd_index); |
+ ExtractHandle(t1.d, handles, fds, msg, &fd_index); |
+ ExtractHandle(t1.e, handles, fds, msg, &fd_index); |
+ ExtractHandle(t1.f, handles, fds, msg, &fd_index); |
+} |
+ |
+template <class MessageType> |
+class HandleExtractor { |
+ public: |
+ explicit HandleExtractor(const IPC::Message* msg) |
+ : msg_(static_cast<MessageType>(msg)) { |
+ } |
+ bool TranslateMessage(std::vector<base::SharedMemoryHandle>* shm_handles, |
+ std::vector<IPC::PlatformFileForTransit>* fds, |
+ IPC::Message* msg) { |
+ typename MessageType::Schema::Param params; |
+ if (!Read(msg, ¶ms)) |
+ return false; |
+ ExtractHandlesImpl(params, shm_handles, fds, msg); |
+ return true; |
+ } |
+ private: |
+ const MessageType* msg_; |
+}; |
+ |
} // namespace |
class NaClIPCAdapter::RewrittenMessage |
@@ -346,54 +446,67 @@ bool NaClIPCAdapter::OnMessageReceived(const IPC::Message& message) { |
// Clear any descriptors left from the prior message. |
locked_data_.nacl_descs_.clear(); |
- PickleIterator it(message); |
+ // Pointer to the "new" message we will rewrite on Windows. On posix, this |
+ // isn't necessary, so it will stay NULL. |
+ IPC::Message new_message_ptr = NULL; |
+#if defined(OS_WIN) |
+ IPC::Message new_msg(message.routing_id(), |
+ PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID, |
+ message.priority()); |
+ new_message_ptr = &new_msg; |
+#endif |
+ ShmHandles handles; |
+ FDs fds; |
switch (message.type()) { |
+ // Note that the case for each message is now pretty much boilerplate... |
+ // We can condense it to a macro if we want to save lines of code. So you |
+ // might get: |
+ // CASE_FOR_MESSAGE(PpapiMsg_PPB_Audio_NotifyAudioStreamCreated); |
+ // CASE_FOR_MESSAGE(PpapiMsg_PPB_AudioInput_NotifyAudioStreamCreated); |
+ // etc. |
case PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID: { |
- int instance_id; |
- int resource_id; |
- int result_code; |
- NaClHandle sock_handle; |
- NaClHandle shm_handle; |
- uint32_t shm_length; |
- if (ReadHostResource(&it, &instance_id, &resource_id) && |
- it.ReadInt(&result_code) && |
- ReadFileDescriptor(message, &it, &sock_handle) && |
- ReadFileDescriptor(message, &it, &shm_handle) && |
- it.ReadUInt32(&shm_length)) { |
- // Our caller, OnMessageReceived, holds the lock for locked_data_. |
- // Import the sync socket. Use DescWrappers to simplify clean up. |
- nacl::DescWrapperFactory factory; |
- scoped_ptr<nacl::DescWrapper> socket_wrapper( |
- factory.ImportSyncSocketHandle(sock_handle)); |
- // Import the shared memory handle and increase its size by 4 bytes to |
- // accommodate the length data we write to signal the host. |
- scoped_ptr<nacl::DescWrapper> shm_wrapper( |
- factory.ImportShmHandle(shm_handle, shm_length + sizeof(uint32))); |
- if (shm_wrapper.get() && socket_wrapper.get()) { |
- locked_data_.nacl_descs_.push_back(socket_wrapper.release()); |
- locked_data_.nacl_descs_.push_back(shm_wrapper.release()); |
- } |
-#if defined(OS_POSIX) |
- SaveMessage(message); |
-#else // defined(OS_POSIX) |
- // On Windows we must rewrite the message to the POSIX representation. |
- IPC::Message new_msg(message.routing_id(), |
- PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID, |
- message.priority()); |
- WriteHostResource(&new_msg, instance_id, resource_id); |
- new_msg.WriteInt(result_code); |
- WriteFileDescriptor(&new_msg, 0); // socket handle, index = 0 |
- WriteFileDescriptor(&new_msg, 1); // shm handle, index = 1 |
- new_msg.WriteUInt32(shm_length); |
- SaveMessage(new_msg); |
-#endif |
- } |
+ HandleExtractor<PpapiMsg_PPBAudio_NotifyAudioStreamCreated> |
+ extractor(message); |
+ if (!extractor.TranslateMessage(msg, &handles, &fds, new_message_ptr)) |
+ return false; |
+ break; |
+ case IPC_REPLY_ID: { |
+ /* TODO(dmichael): Look up the type of the originating message, do |
+ another switch here to deal with any reply messages with handles.*/ |
break; |
} |
- default: { |
- SaveMessage(message); |
+ default: |
+#if defined(OS_WIN) |
+ // There are no handles, and we didn't have to rewrite the new message. |
+ // Just make sure that SaveMessage below saves the valid message, since |
+ // new_msg doesn't have any data. |
+ new_message_ptr = &message; |
+#endif |
+ // default case has nothing to do in posix; we'll save the message |
+ // below. |
+ } |
+ // Now add any descriptors we found to nacl_descs_. These are usually both |
+ // empty, unless we read a message containing a FD or handle. |
+ nacl::DescWrapperFactory factory; |
+ for (ShmHandles::const_iterator iter = handles.begin(); |
+ iter != handles.end(); |
+ ++iter) { |
+ scoped_ptr<nacl::DescWrapper> shm_wrapper( |
+ factory.ImportShmHandle(iter->handle, iter->length)); |
+ if (shm_wrapper.get()) |
+ locked_data_.nacl_descs_.push_back(shm_wrapper.release()); |
+ } |
+ for (FDs::const_iterator iter = fds.begin(); iter != fds.end(); ++iter) { |
+ scoped_ptr<nacl::DescWrapper> socket_wrapper( |
+ factory.ImportSyncSocketHandle(sock_handle)); |
+ if (socket_wrapper.get()) |
+ locked_data_.nacl_descs_.push_back(socket_wrapper.release()); |
} |
} |
+ if (new_message_ptr) |
+ SaveMessage(*new_message_ptr); // For Windows |
+ else |
+ SaveMessage(message); |
} |
cond_var_.Signal(); |
return true; |
@@ -467,6 +580,21 @@ bool NaClIPCAdapter::SendCompleteMessage(const char* buffer, |
if (locked_data_.channel_closed_) |
return false; // TODO(brettw) clean up handles here when we add support! |
+ // Deal with sync messages with handles in the reply. |
+ if (msg->is_sync()) { |
+ if (msg->type() == PpapiHostMsg_PPBImageData_CreateNaCl::ID) { |
+ int id = IPC::SyncMessage::GetMessageId(*msg); |
+ PickleIterator iter(IPC::SyncMessage::GetDataIterator(msg.get())); |
+ int dummy, height, width; |
+ if (iter.ReadInt(&dummy) && // instance |
+ iter.ReadInt(&dummy) && // format |
+ iter.ReadInt(&height) && |
+ iter.ReadInt(&width)) { |
+ uint32_t size = height * width * 4; |
+ locked_data_.pending_image_data_msgs_[id] = size; |
+ } |
+ } |
+ } |
// Actual send must be done on the I/O thread. |
task_runner_->PostTask(FROM_HERE, |
base::Bind(&NaClIPCAdapter::SendMessageOnIOThread, this, |
@@ -496,6 +624,7 @@ void NaClIPCAdapter::SendMessageOnIOThread(scoped_ptr<IPC::Message> message) { |
} |
void NaClIPCAdapter::SaveMessage(const IPC::Message& message) { |
+ lock_.AssertAcquired(); |
// There is some padding in this structure (the "padding" member is 16 |
// bits but this then gets padded to 32 bits). We want to be sure not to |
// leak data to the untrusted plugin, so zero everything out first. |