summaryrefslogtreecommitdiffstats
path: root/ppapi/nacl_irt/manifest_service.cc
blob: 9bf33dee7b09ff977a78bde6e1e1511e8d9f1ba8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ppapi/nacl_irt/manifest_service.h"

#include "base/message_loop/message_loop_proxy.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_channel_proxy.h"
#include "ipc/ipc_sync_message_filter.h"
#include "native_client/src/trusted/service_runtime/include/sys/errno.h"
#include "ppapi/nacl_irt/irt_manifest.h"
#include "ppapi/nacl_irt/plugin_startup.h"
#include "ppapi/proxy/ppapi_messages.h"

namespace ppapi {

const char kFilePrefix[] = "files/";

// IPC channel is asynchronously set up. So, the NaCl process may try to
// send a OpenResource message to the host before the connection is
// established. In such a case, it is necessary to wait for the set up
// completion.
class ManifestMessageFilter : public IPC::SyncMessageFilter {
 public:
  ManifestMessageFilter(base::WaitableEvent* shutdown_event)
      : SyncMessageFilter(shutdown_event),
        connected_event_(
            true /* manual_reset */, false /* initially_signaled */) {
  }

  virtual bool Send(IPC::Message* message) override {
    // Wait until set up is actually done.
    connected_event_.Wait();
    return SyncMessageFilter::Send(message);
  }

  // When set up is done, OnFilterAdded is called on IO thread. Unblocks the
  // Send().
  virtual void OnFilterAdded(IPC::Sender* sender) override {
    SyncMessageFilter::OnFilterAdded(sender);
    connected_event_.Signal();
  }

  // If an error is found, unblocks the Send(), too, to return an error.
  virtual void OnChannelError() override {
    SyncMessageFilter::OnChannelError();
    connected_event_.Signal();
  }

  // Similar to OnChannelError, unblocks the Send() on the channel closing.
  virtual void OnChannelClosing() override {
    SyncMessageFilter::OnChannelClosing();
    connected_event_.Signal();
  }

 private:
  base::WaitableEvent connected_event_;

  DISALLOW_COPY_AND_ASSIGN(ManifestMessageFilter);
};

ManifestService::ManifestService(
    const IPC::ChannelHandle& handle,
    scoped_refptr<base::MessageLoopProxy> io_message_loop,
    base::WaitableEvent* shutdown_event) {
  filter_ = new ManifestMessageFilter(shutdown_event);
  channel_ = IPC::ChannelProxy::Create(handle,
                                       IPC::Channel::MODE_SERVER,
                                       NULL,  // Listener
                                       io_message_loop.get());
  channel_->AddFilter(filter_.get());
}

ManifestService::~ManifestService() {
}

void ManifestService::StartupInitializationComplete() {
  filter_->Send(new PpapiHostMsg_StartupInitializationComplete);
}

bool ManifestService::OpenResource(const char* file, int* fd) {
  // We currently restrict to only allow one concurrent open_resource() call
  // per plugin. This could be fixed by doing a token lookup with
  // NaClProcessMsg_ResolveFileTokenAsyncReply instead of using a
  // global inside components/nacl/loader/nacl_listener.cc
  base::AutoLock lock(open_resource_lock_);

  // OpenResource will return INVALID SerializedHandle, if it is not supported.
  // Specifically, PNaCl doesn't support open resource.
  ppapi::proxy::SerializedHandle ipc_fd;

  // File tokens are ignored here, but needed when the message is processed
  // inside NaClIPCAdapter.
  uint64_t file_token_lo;
  uint64_t file_token_hi;
  if (!filter_->Send(new PpapiHostMsg_OpenResource(
          std::string(kFilePrefix) + file,
          &ipc_fd,
          &file_token_lo,
          &file_token_hi))) {
    LOG(ERROR) << "ManifestService::OpenResource failed:" << file;
    *fd = -1;
    return false;
  }

#if defined(OS_NACL)
  // File tokens are used internally by NaClIPCAdapter and should have
  // been cleared from the message when it is received here.
  // Note that, on Non-SFI NaCl, the IPC channel is directly connected to the
  // renderer process, so NaClIPCAdapter does not work. It means,
  // file_token_{lo,hi} fields may be properly filled, although it is just
  // ignored here.
  CHECK(file_token_lo == 0);
  CHECK(file_token_hi == 0);
#endif

  // Copy the file if we received a valid file descriptor. Otherwise, if we got
  // a reply, the file doesn't exist, so provide an fd of -1.
  // See IrtOpenResource() for how this function's result is interpreted.
  if (ipc_fd.is_file())
    *fd = ipc_fd.descriptor().fd;
  else
    *fd = -1;
  return true;
}

int IrtOpenResource(const char* file, int* fd) {
  // Remove leading '/' character.
  if (file[0] == '/')
    ++file;

  ManifestService* manifest_service = GetManifestService();
  if (manifest_service == NULL ||
      !manifest_service->OpenResource(file, fd)) {
    return NACL_ABI_EIO;
  }
  return (*fd == -1) ? NACL_ABI_ENOENT : 0;
}

}  // namespace ppapi