summaryrefslogtreecommitdiffstats
path: root/ppapi/proxy/ppb_buffer_proxy.cc
blob: c6d8cdd626b427e2e584975d4458117525fccced (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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Copyright (c) 2012 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/proxy/ppb_buffer_proxy.h"

#include <vector>

#include "base/logging.h"
#include "build/build_config.h"
#include "ppapi/c/pp_completion_callback.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_resource.h"
#include "ppapi/c/dev/ppb_buffer_dev.h"
#include "ppapi/proxy/host_dispatcher.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/thunk/enter.h"
#include "ppapi/thunk/resource_creation_api.h"
#include "ppapi/thunk/thunk.h"

namespace ppapi {
namespace proxy {

Buffer::Buffer(const HostResource& resource,
               const base::SharedMemoryHandle& shm_handle,
               uint32_t size)
    : Resource(OBJECT_IS_PROXY, resource),
      shm_(shm_handle, false),
      size_(size),
      map_count_(0) {
}

Buffer::~Buffer() {
  Unmap();
}

thunk::PPB_Buffer_API* Buffer::AsPPB_Buffer_API() {
  return this;
}

PP_Bool Buffer::Describe(uint32_t* size_in_bytes) {
  *size_in_bytes = size_;
  return PP_TRUE;
}

PP_Bool Buffer::IsMapped() {
  return PP_FromBool(map_count_ > 0);
}

void* Buffer::Map() {
  if (map_count_++ == 0)
    shm_.Map(size_);
  return shm_.memory();
}

void Buffer::Unmap() {
  if (--map_count_ == 0)
    shm_.Unmap();
}

int32_t Buffer::GetSharedMemory(int* out_handle) {
  NOTREACHED();
  return PP_ERROR_NOTSUPPORTED;
}

PPB_Buffer_Proxy::PPB_Buffer_Proxy(Dispatcher* dispatcher)
    : InterfaceProxy(dispatcher) {
}

PPB_Buffer_Proxy::~PPB_Buffer_Proxy() {
}

// static
PP_Resource PPB_Buffer_Proxy::CreateProxyResource(PP_Instance instance,
                                                  uint32_t size) {
  PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
  if (!dispatcher)
    return 0;

  HostResource result;
  ppapi::proxy::SerializedHandle shm_handle;
  dispatcher->Send(new PpapiHostMsg_PPBBuffer_Create(
      API_ID_PPB_BUFFER, instance, size, &result, &shm_handle));
  if (result.is_null() || !shm_handle.IsHandleValid() ||
      !shm_handle.is_shmem())
    return 0;

  return AddProxyResource(result, shm_handle.shmem(), size);
}

// static
PP_Resource PPB_Buffer_Proxy::AddProxyResource(
    const HostResource& resource,
    base::SharedMemoryHandle shm_handle,
    uint32_t size) {
  return (new Buffer(resource, shm_handle, size))->GetReference();
}

bool PPB_Buffer_Proxy::OnMessageReceived(const IPC::Message& msg) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(PPB_Buffer_Proxy, msg)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBBuffer_Create, OnMsgCreate)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  // TODO(brettw) handle bad messages!
  return handled;
}

void PPB_Buffer_Proxy::OnMsgCreate(
    PP_Instance instance,
    uint32_t size,
    HostResource* result_resource,
    ppapi::proxy::SerializedHandle* result_shm_handle) {
  // Overwritten below on success.
  result_shm_handle->set_null_shmem();
  HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance);
  if (!dispatcher)
    return;
  if (!dispatcher->permissions().HasPermission(ppapi::PERMISSION_DEV))
    return;

  thunk::EnterResourceCreation enter(instance);
  if (enter.failed())
    return;
  PP_Resource local_buffer_resource = enter.functions()->CreateBuffer(instance,
                                                                      size);
  if (local_buffer_resource == 0)
    return;

  thunk::EnterResourceNoLock<thunk::PPB_Buffer_API> trusted_buffer(
      local_buffer_resource, false);
  if (trusted_buffer.failed())
    return;
  int local_fd;
  if (trusted_buffer.object()->GetSharedMemory(&local_fd) != PP_OK)
    return;

  result_resource->SetHostResource(instance, local_buffer_resource);

  // TODO(piman/brettw): Change trusted interface to return a PP_FileHandle,
  // those casts are ugly.
  base::PlatformFile platform_file =
#if defined(OS_WIN)
      reinterpret_cast<HANDLE>(static_cast<intptr_t>(local_fd));
#elif defined(OS_POSIX)
      local_fd;
#else
  #error Not implemented.
#endif
  result_shm_handle->set_shmem(
      dispatcher->ShareHandleWithRemote(platform_file, false), size);
}

}  // namespace proxy
}  // namespace ppapi