OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/nacl/nacl_ipc_adapter.h" | 5 #include "chrome/nacl/nacl_ipc_adapter.h" |
6 | 6 |
7 #include <limits.h> | 7 #include <limits.h> |
8 #include <string.h> | 8 #include <string.h> |
9 | 9 |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 int resource_id) { | 122 int resource_id) { |
123 message->WriteInt(instance_id); | 123 message->WriteInt(instance_id); |
124 message->WriteInt(resource_id); | 124 message->WriteInt(resource_id); |
125 } | 125 } |
126 | 126 |
127 void WriteFileDescriptor(IPC::Message* message, int index) { | 127 void WriteFileDescriptor(IPC::Message* message, int index) { |
128 message->WriteBool(true); // valid == true | 128 message->WriteBool(true); // valid == true |
129 message->WriteInt(index); | 129 message->WriteInt(index); |
130 } | 130 } |
131 | 131 |
| 132 typedef std::vector<ppapi::proxy::SerializedSharedMemoryHandle> ShmHandles; |
| 133 typedef std::vector<ppapi::proxy::SerializedFileDescriptor> FDs; |
| 134 |
| 135 void ExtractHandle(const ppapi::proxy::SerializedSharedMemoryHandle& handle, |
| 136 ShmHandles* handles, FDs* /* fds */, IPC::Message* msg, |
| 137 int* index) { |
| 138 handles->push_back(handle); |
| 139 if (msg) |
| 140 WriteFileDescriptor(msg, (*index)++); |
| 141 } |
| 142 void ExtractHandle(const ppapi::proxy::SerializedFileDescriptor& fd, |
| 143 ShmHandles* /* handles */, FDs* fds, IPC::Message* msg, |
| 144 int* index) { |
| 145 fds->push_back(fd); |
| 146 if (msg) |
| 147 WriteFileDescriptor(msg, (*index)++); |
| 148 } |
| 149 template <class T> |
| 150 ExtractHandle(cont T& param, ShmHandles* /* handles */, FDs* /* fds */, |
| 151 IPC::Message* msg, int* index) { |
| 152 // It's not a handle, so just write to the output message, if necessary. |
| 153 if (msg) |
| 154 IPC::WriteParam(m, param); |
| 155 } |
| 156 |
| 157 // These just break apart the given tuple and run ExtractHandle over each param. |
| 158 // The idea is to extract any handles in the tuple, while writing all data to |
| 159 // msg (if msg is valid). The msg will only be valid on Windows, where we need |
| 160 // to re-write the message to include the handles in POSIX style for NaCl. |
| 161 template <class A> |
| 162 void ExtractHandlesImpl(const Tuple1<A>& t1, ShmHandles* handles, FDs* fds, |
| 163 IPC::Message* msg) { |
| 164 int fd_index = 0; |
| 165 ExtractHandle(t1.a, handles, fds, msg, &fd_index); |
| 166 } |
| 167 template <class A, class B> |
| 168 void ExtractHandlesImpl(const Tuple2<A, B>& t1, ShmHandles* handles, FDs* fds, |
| 169 IPC::Message* msg) { |
| 170 int fd_index = 0; |
| 171 ExtractHandle(t1.a, handles, fds, msg, &fd_index); |
| 172 ExtractHandle(t1.b, handles, fds, msg, &fd_index); |
| 173 } |
| 174 template <class A, class B, class C> |
| 175 void ExtractHandlesImpl(const Tuple3<A, B, C>& t1, ShmHandles* handles, |
| 176 FDs* fds, IPC::Message* msg) { |
| 177 int fd_index = 0; |
| 178 ExtractHandle(t1.a, handles, fds, msg, &fd_index); |
| 179 ExtractHandle(t1.b, handles, fds, msg, &fd_index); |
| 180 ExtractHandle(t1.c, handles, fds, msg, &fd_index); |
| 181 } |
| 182 template <class A, class B, class C, class D> |
| 183 void ExtractHandlesImpl(const Tuple4<A, B, C, D>& t1, ShmHandles* handles, |
| 184 FDs* fds, IPC::Message* msg) { |
| 185 int fd_index = 0; |
| 186 ExtractHandle(t1.a, handles, fds, msg, &fd_index); |
| 187 ExtractHandle(t1.b, handles, fds, msg, &fd_index); |
| 188 ExtractHandle(t1.c, handles, fds, msg, &fd_index); |
| 189 ExtractHandle(t1.d, handles, fds, msg, &fd_index); |
| 190 } |
| 191 template <class A, class B, class C, class D, class E> |
| 192 void ExtractHandlesImpl(const Tuple5<A, B, C, D, E>& t1, ShmHandles* handles, |
| 193 FDs* fds, IPC::Message* msg) { |
| 194 int fd_index = 0; |
| 195 ExtractHandle(t1.a, handles, fds, msg, &fd_index); |
| 196 ExtractHandle(t1.b, handles, fds, msg, &fd_index); |
| 197 ExtractHandle(t1.c, handles, fds, msg, &fd_index); |
| 198 ExtractHandle(t1.d, handles, fds, msg, &fd_index); |
| 199 ExtractHandle(t1.e, handles, fds, msg, &fd_index); |
| 200 } |
| 201 template <class A, class B, class C, class D, class E, class F> |
| 202 void ExtractHandlesImpl(const Tuple6<A, B, C, D, E, F>& t1, ShmHandles* handles, |
| 203 FDs* fds, IPC::Message* msg) { |
| 204 int fd_index = 0; |
| 205 ExtractHandle(t1.a, handles, fds, msg, &fd_index); |
| 206 ExtractHandle(t1.b, handles, fds, msg, &fd_index); |
| 207 ExtractHandle(t1.c, handles, fds, msg, &fd_index); |
| 208 ExtractHandle(t1.d, handles, fds, msg, &fd_index); |
| 209 ExtractHandle(t1.e, handles, fds, msg, &fd_index); |
| 210 ExtractHandle(t1.f, handles, fds, msg, &fd_index); |
| 211 } |
| 212 |
| 213 template <class MessageType> |
| 214 class HandleExtractor { |
| 215 public: |
| 216 explicit HandleExtractor(const IPC::Message* msg) |
| 217 : msg_(static_cast<MessageType>(msg)) { |
| 218 } |
| 219 bool TranslateMessage(std::vector<base::SharedMemoryHandle>* shm_handles, |
| 220 std::vector<IPC::PlatformFileForTransit>* fds, |
| 221 IPC::Message* msg) { |
| 222 typename MessageType::Schema::Param params; |
| 223 if (!Read(msg, ¶ms)) |
| 224 return false; |
| 225 ExtractHandlesImpl(params, shm_handles, fds, msg); |
| 226 return true; |
| 227 } |
| 228 private: |
| 229 const MessageType* msg_; |
| 230 }; |
| 231 |
132 } // namespace | 232 } // namespace |
133 | 233 |
134 class NaClIPCAdapter::RewrittenMessage | 234 class NaClIPCAdapter::RewrittenMessage |
135 : public base::RefCounted<RewrittenMessage> { | 235 : public base::RefCounted<RewrittenMessage> { |
136 public: | 236 public: |
137 RewrittenMessage(); | 237 RewrittenMessage(); |
138 | 238 |
139 bool is_consumed() const { return data_read_cursor_ == data_len_; } | 239 bool is_consumed() const { return data_read_cursor_ == data_len_; } |
140 | 240 |
141 void SetData(const NaClIPCAdapter::NaClMessageHeader& header, | 241 void SetData(const NaClIPCAdapter::NaClMessageHeader& header, |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
339 } | 439 } |
340 #endif | 440 #endif |
341 | 441 |
342 bool NaClIPCAdapter::OnMessageReceived(const IPC::Message& message) { | 442 bool NaClIPCAdapter::OnMessageReceived(const IPC::Message& message) { |
343 { | 443 { |
344 base::AutoLock lock(lock_); | 444 base::AutoLock lock(lock_); |
345 | 445 |
346 // Clear any descriptors left from the prior message. | 446 // Clear any descriptors left from the prior message. |
347 locked_data_.nacl_descs_.clear(); | 447 locked_data_.nacl_descs_.clear(); |
348 | 448 |
349 PickleIterator it(message); | 449 // Pointer to the "new" message we will rewrite on Windows. On posix, this |
| 450 // isn't necessary, so it will stay NULL. |
| 451 IPC::Message new_message_ptr = NULL; |
| 452 #if defined(OS_WIN) |
| 453 IPC::Message new_msg(message.routing_id(), |
| 454 PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID, |
| 455 message.priority()); |
| 456 new_message_ptr = &new_msg; |
| 457 #endif |
| 458 ShmHandles handles; |
| 459 FDs fds; |
350 switch (message.type()) { | 460 switch (message.type()) { |
| 461 // Note that the case for each message is now pretty much boilerplate... |
| 462 // We can condense it to a macro if we want to save lines of code. So you |
| 463 // might get: |
| 464 // CASE_FOR_MESSAGE(PpapiMsg_PPB_Audio_NotifyAudioStreamCreated); |
| 465 // CASE_FOR_MESSAGE(PpapiMsg_PPB_AudioInput_NotifyAudioStreamCreated); |
| 466 // etc. |
351 case PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID: { | 467 case PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID: { |
352 int instance_id; | 468 HandleExtractor<PpapiMsg_PPBAudio_NotifyAudioStreamCreated> |
353 int resource_id; | 469 extractor(message); |
354 int result_code; | 470 if (!extractor.TranslateMessage(msg, &handles, &fds, new_message_ptr)) |
355 NaClHandle sock_handle; | 471 return false; |
356 NaClHandle shm_handle; | 472 break; |
357 uint32_t shm_length; | 473 case IPC_REPLY_ID: { |
358 if (ReadHostResource(&it, &instance_id, &resource_id) && | 474 /* TODO(dmichael): Look up the type of the originating message, do |
359 it.ReadInt(&result_code) && | 475 another switch here to deal with any reply messages with handles.*/ |
360 ReadFileDescriptor(message, &it, &sock_handle) && | |
361 ReadFileDescriptor(message, &it, &shm_handle) && | |
362 it.ReadUInt32(&shm_length)) { | |
363 // Our caller, OnMessageReceived, holds the lock for locked_data_. | |
364 // Import the sync socket. Use DescWrappers to simplify clean up. | |
365 nacl::DescWrapperFactory factory; | |
366 scoped_ptr<nacl::DescWrapper> socket_wrapper( | |
367 factory.ImportSyncSocketHandle(sock_handle)); | |
368 // Import the shared memory handle and increase its size by 4 bytes to | |
369 // accommodate the length data we write to signal the host. | |
370 scoped_ptr<nacl::DescWrapper> shm_wrapper( | |
371 factory.ImportShmHandle(shm_handle, shm_length + sizeof(uint32))); | |
372 if (shm_wrapper.get() && socket_wrapper.get()) { | |
373 locked_data_.nacl_descs_.push_back(socket_wrapper.release()); | |
374 locked_data_.nacl_descs_.push_back(shm_wrapper.release()); | |
375 } | |
376 #if defined(OS_POSIX) | |
377 SaveMessage(message); | |
378 #else // defined(OS_POSIX) | |
379 // On Windows we must rewrite the message to the POSIX representation. | |
380 IPC::Message new_msg(message.routing_id(), | |
381 PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID, | |
382 message.priority()); | |
383 WriteHostResource(&new_msg, instance_id, resource_id); | |
384 new_msg.WriteInt(result_code); | |
385 WriteFileDescriptor(&new_msg, 0); // socket handle, index = 0 | |
386 WriteFileDescriptor(&new_msg, 1); // shm handle, index = 1 | |
387 new_msg.WriteUInt32(shm_length); | |
388 SaveMessage(new_msg); | |
389 #endif | |
390 } | |
391 break; | 476 break; |
392 } | 477 } |
393 default: { | 478 default: |
394 SaveMessage(message); | 479 #if defined(OS_WIN) |
| 480 // There are no handles, and we didn't have to rewrite the new message. |
| 481 // Just make sure that SaveMessage below saves the valid message, since |
| 482 // new_msg doesn't have any data. |
| 483 new_message_ptr = &message; |
| 484 #endif |
| 485 // default case has nothing to do in posix; we'll save the message |
| 486 // below. |
| 487 } |
| 488 // Now add any descriptors we found to nacl_descs_. These are usually both |
| 489 // empty, unless we read a message containing a FD or handle. |
| 490 nacl::DescWrapperFactory factory; |
| 491 for (ShmHandles::const_iterator iter = handles.begin(); |
| 492 iter != handles.end(); |
| 493 ++iter) { |
| 494 scoped_ptr<nacl::DescWrapper> shm_wrapper( |
| 495 factory.ImportShmHandle(iter->handle, iter->length)); |
| 496 if (shm_wrapper.get()) |
| 497 locked_data_.nacl_descs_.push_back(shm_wrapper.release()); |
| 498 } |
| 499 for (FDs::const_iterator iter = fds.begin(); iter != fds.end(); ++iter) { |
| 500 scoped_ptr<nacl::DescWrapper> socket_wrapper( |
| 501 factory.ImportSyncSocketHandle(sock_handle)); |
| 502 if (socket_wrapper.get()) |
| 503 locked_data_.nacl_descs_.push_back(socket_wrapper.release()); |
395 } | 504 } |
396 } | 505 } |
| 506 if (new_message_ptr) |
| 507 SaveMessage(*new_message_ptr); // For Windows |
| 508 else |
| 509 SaveMessage(message); |
397 } | 510 } |
398 cond_var_.Signal(); | 511 cond_var_.Signal(); |
399 return true; | 512 return true; |
400 } | 513 } |
401 | 514 |
402 void NaClIPCAdapter::OnChannelConnected(int32 peer_pid) { | 515 void NaClIPCAdapter::OnChannelConnected(int32 peer_pid) { |
403 } | 516 } |
404 | 517 |
405 void NaClIPCAdapter::OnChannelError() { | 518 void NaClIPCAdapter::OnChannelError() { |
406 CloseChannel(); | 519 CloseChannel(); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
460 | 573 |
461 // Technically we didn't have to do any of the previous work in the lock. But | 574 // Technically we didn't have to do any of the previous work in the lock. But |
462 // sometimes our buffer will point to the to_be_sent_ string which is | 575 // sometimes our buffer will point to the to_be_sent_ string which is |
463 // protected by the lock, and it's messier to factor Send() such that it can | 576 // protected by the lock, and it's messier to factor Send() such that it can |
464 // unlock for us. Holding the lock for the message construction, which is | 577 // unlock for us. Holding the lock for the message construction, which is |
465 // just some memcpys, shouldn't be a big deal. | 578 // just some memcpys, shouldn't be a big deal. |
466 lock_.AssertAcquired(); | 579 lock_.AssertAcquired(); |
467 if (locked_data_.channel_closed_) | 580 if (locked_data_.channel_closed_) |
468 return false; // TODO(brettw) clean up handles here when we add support! | 581 return false; // TODO(brettw) clean up handles here when we add support! |
469 | 582 |
| 583 // Deal with sync messages with handles in the reply. |
| 584 if (msg->is_sync()) { |
| 585 if (msg->type() == PpapiHostMsg_PPBImageData_CreateNaCl::ID) { |
| 586 int id = IPC::SyncMessage::GetMessageId(*msg); |
| 587 PickleIterator iter(IPC::SyncMessage::GetDataIterator(msg.get())); |
| 588 int dummy, height, width; |
| 589 if (iter.ReadInt(&dummy) && // instance |
| 590 iter.ReadInt(&dummy) && // format |
| 591 iter.ReadInt(&height) && |
| 592 iter.ReadInt(&width)) { |
| 593 uint32_t size = height * width * 4; |
| 594 locked_data_.pending_image_data_msgs_[id] = size; |
| 595 } |
| 596 } |
| 597 } |
470 // Actual send must be done on the I/O thread. | 598 // Actual send must be done on the I/O thread. |
471 task_runner_->PostTask(FROM_HERE, | 599 task_runner_->PostTask(FROM_HERE, |
472 base::Bind(&NaClIPCAdapter::SendMessageOnIOThread, this, | 600 base::Bind(&NaClIPCAdapter::SendMessageOnIOThread, this, |
473 base::Passed(&msg))); | 601 base::Passed(&msg))); |
474 return true; | 602 return true; |
475 } | 603 } |
476 | 604 |
477 void NaClIPCAdapter::ClearToBeSent() { | 605 void NaClIPCAdapter::ClearToBeSent() { |
478 lock_.AssertAcquired(); | 606 lock_.AssertAcquired(); |
479 | 607 |
480 // Don't let the string keep its buffer behind our back. | 608 // Don't let the string keep its buffer behind our back. |
481 std::string empty; | 609 std::string empty; |
482 locked_data_.to_be_sent_.swap(empty); | 610 locked_data_.to_be_sent_.swap(empty); |
483 } | 611 } |
484 | 612 |
485 void NaClIPCAdapter::ConnectChannelOnIOThread() { | 613 void NaClIPCAdapter::ConnectChannelOnIOThread() { |
486 if (!io_thread_data_.channel_->Connect()) | 614 if (!io_thread_data_.channel_->Connect()) |
487 NOTREACHED(); | 615 NOTREACHED(); |
488 } | 616 } |
489 | 617 |
490 void NaClIPCAdapter::CloseChannelOnIOThread() { | 618 void NaClIPCAdapter::CloseChannelOnIOThread() { |
491 io_thread_data_.channel_->Close(); | 619 io_thread_data_.channel_->Close(); |
492 } | 620 } |
493 | 621 |
494 void NaClIPCAdapter::SendMessageOnIOThread(scoped_ptr<IPC::Message> message) { | 622 void NaClIPCAdapter::SendMessageOnIOThread(scoped_ptr<IPC::Message> message) { |
495 io_thread_data_.channel_->Send(message.release()); | 623 io_thread_data_.channel_->Send(message.release()); |
496 } | 624 } |
497 | 625 |
498 void NaClIPCAdapter::SaveMessage(const IPC::Message& message) { | 626 void NaClIPCAdapter::SaveMessage(const IPC::Message& message) { |
| 627 lock_.AssertAcquired(); |
499 // There is some padding in this structure (the "padding" member is 16 | 628 // There is some padding in this structure (the "padding" member is 16 |
500 // bits but this then gets padded to 32 bits). We want to be sure not to | 629 // bits but this then gets padded to 32 bits). We want to be sure not to |
501 // leak data to the untrusted plugin, so zero everything out first. | 630 // leak data to the untrusted plugin, so zero everything out first. |
502 NaClMessageHeader header; | 631 NaClMessageHeader header; |
503 memset(&header, 0, sizeof(NaClMessageHeader)); | 632 memset(&header, 0, sizeof(NaClMessageHeader)); |
504 | 633 |
505 header.payload_size = static_cast<uint32>(message.payload_size()); | 634 header.payload_size = static_cast<uint32>(message.payload_size()); |
506 header.routing = message.routing_id(); | 635 header.routing = message.routing_id(); |
507 header.type = message.type(); | 636 header.type = message.type(); |
508 header.flags = message.flags(); | 637 header.flags = message.flags(); |
509 header.num_fds = static_cast<int>(locked_data_.nacl_descs_.size()); | 638 header.num_fds = static_cast<int>(locked_data_.nacl_descs_.size()); |
510 | 639 |
511 scoped_refptr<RewrittenMessage> dest(new RewrittenMessage); | 640 scoped_refptr<RewrittenMessage> dest(new RewrittenMessage); |
512 dest->SetData(header, message.payload(), message.payload_size()); | 641 dest->SetData(header, message.payload(), message.payload_size()); |
513 locked_data_.to_be_received_.push(dest); | 642 locked_data_.to_be_received_.push(dest); |
514 } | 643 } |
515 | 644 |
OLD | NEW |