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 16namespace ppapi { 17 18const 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. 24class 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 63ManifestService::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); 72 channel_->AddFilter(filter_.get()); 73} 74 75ManifestService::~ManifestService() { 76} 77 78void ManifestService::StartupInitializationComplete() { 79 filter_->Send(new PpapiHostMsg_StartupInitializationComplete); 80} 81 82bool ManifestService::OpenResource(const char* file, int* fd) { 83 // OpenResource will return INVALID SerializedHandle, if it is not supported. 84 // Specifically, PNaCl doesn't support open resource. 85 ppapi::proxy::SerializedHandle ipc_fd; 86 if (!filter_->Send(new PpapiHostMsg_OpenResource( 87 std::string(kFilePrefix) + file, &ipc_fd)) || 88 !ipc_fd.is_file()) { 89 LOG(ERROR) << "ManifestService::OpenResource failed:" << file; 90 *fd = -1; 91 return false; 92 } 93 94 *fd = ipc_fd.descriptor().fd; 95 return true; 96} 97 98int IrtOpenResource(const char* file, int* fd) { 99 // Remove leading '/' character. 100 if (file[0] == '/') 101 ++file; 102 103 ManifestService* manifest_service = GetManifestService(); 104 if (manifest_service == NULL || 105 !manifest_service->OpenResource(file, fd)) { 106 return NACL_ABI_EIO; 107 } 108 109 return (*fd == -1) ? NACL_ABI_ENOENT : 0; 110} 111 112} // namespace ppapi 113