1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ppapi/nacl_irt/manifest_service.h" 6 7 #include "base/message_loop/message_loop_proxy.h" 8 #include "ipc/ipc_channel_handle.h" 9 #include "ipc/ipc_channel_proxy.h" 10 #include "ipc/ipc_sync_message_filter.h" 11 #include "native_client/src/trusted/service_runtime/include/sys/errno.h" 12 #include "ppapi/nacl_irt/irt_manifest.h" 13 #include "ppapi/nacl_irt/plugin_startup.h" 14 #include "ppapi/proxy/ppapi_messages.h" 15 16 namespace ppapi { 17 18 const char kFilePrefix[] = "files/"; 19 20 // IPC channel is asynchronously set up. So, the NaCl process may try to 21 // send a OpenResource message to the host before the connection is 22 // established. In such a case, it is necessary to wait for the set up 23 // completion. 24 class ManifestMessageFilter : public IPC::SyncMessageFilter { 25 public: 26 ManifestMessageFilter(base::WaitableEvent* shutdown_event) 27 : SyncMessageFilter(shutdown_event), 28 connected_event_( 29 true /* manual_reset */, false /* initially_signaled */) { 30 } 31 32 virtual bool Send(IPC::Message* message) OVERRIDE { 33 // Wait until set up is actually done. 34 connected_event_.Wait(); 35 return SyncMessageFilter::Send(message); 36 } 37 38 // When set up is done, OnFilterAdded is called on IO thread. Unblocks the 39 // Send(). 40 virtual void OnFilterAdded(IPC::Sender* sender) OVERRIDE { 41 SyncMessageFilter::OnFilterAdded(sender); 42 connected_event_.Signal(); 43 } 44 45 // If an error is found, unblocks the Send(), too, to return an error. 46 virtual void OnChannelError() OVERRIDE { 47 SyncMessageFilter::OnChannelError(); 48 connected_event_.Signal(); 49 } 50 51 // Similar to OnChannelError, unblocks the Send() on the channel closing. 52 virtual void OnChannelClosing() OVERRIDE { 53 SyncMessageFilter::OnChannelClosing(); 54 connected_event_.Signal(); 55 } 56 57 private: 58 base::WaitableEvent connected_event_; 59 60 DISALLOW_COPY_AND_ASSIGN(ManifestMessageFilter); 61 }; 62 63 ManifestService::ManifestService( 64 const IPC::ChannelHandle& handle, 65 scoped_refptr<base::MessageLoopProxy> io_message_loop, 66 base::WaitableEvent* shutdown_event) { 67 filter_ = new ManifestMessageFilter(shutdown_event); 68 channel_ = IPC::ChannelProxy::Create(handle, 69 IPC::Channel::MODE_SERVER, 70 NULL, // Listener 71 io_message_loop.get()); 72 channel_->AddFilter(filter_.get()); 73 } 74 75 ManifestService::~ManifestService() { 76 } 77 78 void ManifestService::StartupInitializationComplete() { 79 filter_->Send(new PpapiHostMsg_StartupInitializationComplete); 80 } 81 82 bool ManifestService::OpenResource(const char* file, int* fd) { 83 // We currently restrict to only allow one concurrent open_resource() call 84 // per plugin. This could be fixed by doing a token lookup with 85 // NaClProcessMsg_ResolveFileTokenAsyncReply instead of using a 86 // global inside components/nacl/loader/nacl_listener.cc 87 base::AutoLock lock(open_resource_lock_); 88 89 // OpenResource will return INVALID SerializedHandle, if it is not supported. 90 // Specifically, PNaCl doesn't support open resource. 91 ppapi::proxy::SerializedHandle ipc_fd; 92 93 // File tokens are ignored here, but needed when the message is processed 94 // inside NaClIPCAdapter. 95 uint64_t file_token_lo; 96 uint64_t file_token_hi; 97 if (!filter_->Send(new PpapiHostMsg_OpenResource( 98 std::string(kFilePrefix) + file, 99 &ipc_fd, 100 &file_token_lo, 101 &file_token_hi))) { 102 LOG(ERROR) << "ManifestService::OpenResource failed:" << file; 103 *fd = -1; 104 return false; 105 } 106 107 #if defined(OS_NACL) 108 // File tokens are used internally by NaClIPCAdapter and should have 109 // been cleared from the message when it is received here. 110 // Note that, on Non-SFI NaCl, the IPC channel is directly connected to the 111 // renderer process, so NaClIPCAdapter does not work. It means, 112 // file_token_{lo,hi} fields may be properly filled, although it is just 113 // ignored here. 114 CHECK(file_token_lo == 0); 115 CHECK(file_token_hi == 0); 116 #endif 117 118 // Copy the file if we received a valid file descriptor. Otherwise, if we got 119 // a reply, the file doesn't exist, so provide an fd of -1. 120 // See IrtOpenResource() for how this function's result is interpreted. 121 if (ipc_fd.is_file()) 122 *fd = ipc_fd.descriptor().fd; 123 else 124 *fd = -1; 125 return true; 126 } 127 128 int IrtOpenResource(const char* file, int* fd) { 129 // Remove leading '/' character. 130 if (file[0] == '/') 131 ++file; 132 133 ManifestService* manifest_service = GetManifestService(); 134 if (manifest_service == NULL || 135 !manifest_service->OpenResource(file, fd)) { 136 return NACL_ABI_EIO; 137 } 138 return (*fd == -1) ? NACL_ABI_ENOENT : 0; 139 } 140 141 } // namespace ppapi 142