10529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
20529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Use of this source code is governed by a BSD-style license that can be
30529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// found in the LICENSE file.
40529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
50529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "ppapi/nacl_irt/manifest_service.h"
60529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
70529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/message_loop/message_loop_proxy.h"
80529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "ipc/ipc_channel_handle.h"
90529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "ipc/ipc_channel_proxy.h"
100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "ipc/ipc_sync_message_filter.h"
11010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "native_client/src/trusted/service_runtime/include/sys/errno.h"
12010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ppapi/nacl_irt/irt_manifest.h"
13010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ppapi/nacl_irt/plugin_startup.h"
140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "ppapi/proxy/ppapi_messages.h"
150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochnamespace ppapi {
170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
18010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)const char kFilePrefix[] = "files/";
19010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// IPC channel is asynchronously set up. So, the NaCl process may try to
21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// send a OpenResource message to the host before the connection is
22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// established. In such a case, it is necessary to wait for the set up
23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// completion.
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class ManifestMessageFilter : public IPC::SyncMessageFilter {
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public:
26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ManifestMessageFilter(base::WaitableEvent* shutdown_event)
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      : SyncMessageFilter(shutdown_event),
28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        connected_event_(
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            true /* manual_reset */, false /* initially_signaled */) {
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual bool Send(IPC::Message* message) OVERRIDE {
33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Wait until set up is actually done.
34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    connected_event_.Wait();
35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return SyncMessageFilter::Send(message);
36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // When set up is done, OnFilterAdded is called on IO thread. Unblocks the
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Send().
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual void OnFilterAdded(IPC::Sender* sender) OVERRIDE {
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    SyncMessageFilter::OnFilterAdded(sender);
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    connected_event_.Signal();
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // If an error is found, unblocks the Send(), too, to return an error.
46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual void OnChannelError() OVERRIDE {
47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    SyncMessageFilter::OnChannelError();
48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    connected_event_.Signal();
49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Similar to OnChannelError, unblocks the Send() on the channel closing.
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual void OnChannelClosing() OVERRIDE {
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    SyncMessageFilter::OnChannelClosing();
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    connected_event_.Signal();
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) private:
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::WaitableEvent connected_event_;
59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ManifestMessageFilter);
61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)};
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
630529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochManifestService::ManifestService(
640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const IPC::ChannelHandle& handle,
650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    scoped_refptr<base::MessageLoopProxy> io_message_loop,
660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    base::WaitableEvent* shutdown_event) {
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  filter_ = new ManifestMessageFilter(shutdown_event);
6846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  channel_ = IPC::ChannelProxy::Create(handle,
690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       IPC::Channel::MODE_SERVER,
70010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                       NULL,  // Listener
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       io_message_loop.get());
720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  channel_->AddFilter(filter_.get());
730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
750529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochManifestService::~ManifestService() {
760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid ManifestService::StartupInitializationComplete() {
790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  filter_->Send(new PpapiHostMsg_StartupInitializationComplete);
800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
82010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool ManifestService::OpenResource(const char* file, int* fd) {
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // We currently restrict to only allow one concurrent open_resource() call
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // per plugin. This could be fixed by doing a token lookup with
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // NaClProcessMsg_ResolveFileTokenAsyncReply instead of using a
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // global inside components/nacl/loader/nacl_listener.cc
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::AutoLock lock(open_resource_lock_);
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
89010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // OpenResource will return INVALID SerializedHandle, if it is not supported.
90010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Specifically, PNaCl doesn't support open resource.
91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  ppapi::proxy::SerializedHandle ipc_fd;
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // File tokens are ignored here, but needed when the message is processed
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // inside NaClIPCAdapter.
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  uint64_t file_token_lo;
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  uint64_t file_token_hi;
97010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!filter_->Send(new PpapiHostMsg_OpenResource(
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          std::string(kFilePrefix) + file,
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          &ipc_fd,
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          &file_token_lo,
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          &file_token_hi))) {
102010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    LOG(ERROR) << "ManifestService::OpenResource failed:" << file;
103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    *fd = -1;
104010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return false;
105010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
106010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if defined(OS_NACL)
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // File tokens are used internally by NaClIPCAdapter and should have
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // been cleared from the message when it is received here.
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Note that, on Non-SFI NaCl, the IPC channel is directly connected to the
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // renderer process, so NaClIPCAdapter does not work. It means,
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // file_token_{lo,hi} fields may be properly filled, although it is just
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // ignored here.
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK(file_token_lo == 0);
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK(file_token_hi == 0);
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Copy the file if we received a valid file descriptor. Otherwise, if we got
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // a reply, the file doesn't exist, so provide an fd of -1.
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // See IrtOpenResource() for how this function's result is interpreted.
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (ipc_fd.is_file())
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    *fd = ipc_fd.descriptor().fd;
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  else
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    *fd = -1;
125010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return true;
126010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
127010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
128010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)int IrtOpenResource(const char* file, int* fd) {
129010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Remove leading '/' character.
130010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (file[0] == '/')
131010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    ++file;
132010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
133010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  ManifestService* manifest_service = GetManifestService();
134010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (manifest_service == NULL ||
135010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      !manifest_service->OpenResource(file, fd)) {
136010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return NACL_ABI_EIO;
137010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
138010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return (*fd == -1) ? NACL_ABI_ENOENT : 0;
139010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
140010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
1410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}  // namespace ppapi
142