1 // Copyright 2016 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 "content/browser/renderer_host/pepper/pepper_vpn_provider_message_filter_chromeos.h"
6 
7 #include "base/bind.h"
8 #include "content/public/browser/browser_task_traits.h"
9 #include "content/public/browser/browser_thread.h"
10 #include "content/public/browser/content_browser_client.h"
11 #include "content/public/browser/pepper_vpn_provider_resource_host_proxy.h"
12 #include "content/public/browser/render_process_host.h"
13 #include "content/public/browser/site_instance.h"
14 #include "content/public/common/content_client.h"
15 #include "ppapi/host/dispatch_host_message.h"
16 #include "ppapi/proxy/ppapi_messages.h"
17 
18 namespace {
19 
20 // Shared memory buffer configuration.
21 const size_t kMaxBufferedPackets = 128;
22 const size_t kMaxPacketSize = 2048;                               // 2 KB
23 const size_t kBufferSize = kMaxBufferedPackets * kMaxPacketSize;  // 256 KB
24 
25 class PepperVpnProviderResourceHostProxyImpl
26     : public content::PepperVpnProviderResourceHostProxy {
27  public:
28   explicit PepperVpnProviderResourceHostProxyImpl(
29       base::WeakPtr<content::PepperVpnProviderMessageFilter>
30           vpn_message_filter);
31 
32   void SendOnPacketReceived(const std::vector<char>& packet) override;
33   void SendOnUnbind() override;
34 
35  private:
36   base::WeakPtr<content::PepperVpnProviderMessageFilter> vpn_message_filter_;
37 
38   DISALLOW_COPY_AND_ASSIGN(PepperVpnProviderResourceHostProxyImpl);
39 };
40 
PepperVpnProviderResourceHostProxyImpl(base::WeakPtr<content::PepperVpnProviderMessageFilter> vpn_message_filter)41 PepperVpnProviderResourceHostProxyImpl::PepperVpnProviderResourceHostProxyImpl(
42     base::WeakPtr<content::PepperVpnProviderMessageFilter> vpn_message_filter)
43     : vpn_message_filter_(vpn_message_filter) {}
44 
SendOnPacketReceived(const std::vector<char> & packet)45 void PepperVpnProviderResourceHostProxyImpl::SendOnPacketReceived(
46     const std::vector<char>& packet) {
47   if (vpn_message_filter_)
48     vpn_message_filter_->SendOnPacketReceived(packet);
49 }
50 
SendOnUnbind()51 void PepperVpnProviderResourceHostProxyImpl::SendOnUnbind() {
52   if (vpn_message_filter_)
53     vpn_message_filter_->SendOnUnbind();
54 }
55 
56 }  // namespace
57 
58 namespace content {
59 
PepperVpnProviderMessageFilter(BrowserPpapiHostImpl * host,PP_Instance instance)60 PepperVpnProviderMessageFilter::PepperVpnProviderMessageFilter(
61     BrowserPpapiHostImpl* host,
62     PP_Instance instance)
63     : browser_context_(nullptr), bound_(false) {
64   DCHECK(host);
65 
66   document_url_ = host->GetDocumentURLForInstance(instance);
67 
68   int render_process_id, unused;
69   bool result =
70       host->GetRenderFrameIDsForInstance(instance, &render_process_id, &unused);
71   DCHECK(result);
72 
73   RenderProcessHost* render_process_host =
74       RenderProcessHost::FromID(render_process_id);
75   DCHECK(render_process_host);
76 
77   browser_context_ = render_process_host->GetBrowserContext();
78 
79   vpn_service_proxy_ =
80       content::GetContentClient()->browser()->GetVpnServiceProxy(
81           browser_context_);
82 }
83 
~PepperVpnProviderMessageFilter()84 PepperVpnProviderMessageFilter::~PepperVpnProviderMessageFilter() {
85   if (bound_ && resource_host()) {
86     resource_host()->host()->SendUnsolicitedReply(
87         resource_host()->pp_resource(), PpapiPluginMsg_VpnProvider_OnUnbind());
88   }
89 }
90 
91 scoped_refptr<base::SequencedTaskRunner>
OverrideTaskRunnerForMessage(const IPC::Message & message)92 PepperVpnProviderMessageFilter::OverrideTaskRunnerForMessage(
93     const IPC::Message& message) {
94   switch (message.type()) {
95     case PpapiHostMsg_VpnProvider_Bind::ID:
96     case PpapiHostMsg_VpnProvider_SendPacket::ID:
97     case PpapiHostMsg_VpnProvider_OnPacketReceivedReply::ID:
98       return GetUIThreadTaskRunner({});
99   }
100   return nullptr;
101 }
102 
OnResourceMessageReceived(const IPC::Message & msg,ppapi::host::HostMessageContext * context)103 int32_t PepperVpnProviderMessageFilter::OnResourceMessageReceived(
104     const IPC::Message& msg,
105     ppapi::host::HostMessageContext* context) {
106   PPAPI_BEGIN_MESSAGE_MAP(PepperVpnProviderMessageFilter, msg)
107     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VpnProvider_Bind, OnBind)
108     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VpnProvider_SendPacket,
109                                       OnSendPacket)
110     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
111         PpapiHostMsg_VpnProvider_OnPacketReceivedReply, OnPacketReceivedReply)
112   PPAPI_END_MESSAGE_MAP()
113   return PP_ERROR_FAILED;
114 }
115 
SendOnPacketReceived(const std::vector<char> & packet)116 void PepperVpnProviderMessageFilter::SendOnPacketReceived(
117     const std::vector<char>& packet) {
118   if (packet.size() == 0 || packet.size() > kMaxPacketSize)
119     return;
120 
121   uint32_t id;
122   if (recv_packet_buffer_ && recv_packet_buffer_->GetAvailable(&id)) {
123     recv_packet_buffer_->SetAvailable(id, false);
124     DoPacketReceived(packet, id);
125   } else {
126     received_packets_.push(packet);
127   }
128 }
129 
SendOnUnbind()130 void PepperVpnProviderMessageFilter::SendOnUnbind() {
131   configuration_name_.clear();
132   configuration_id_.clear();
133   bound_ = false;
134 
135   send_packet_buffer_.reset();
136   recv_packet_buffer_.reset();
137 
138   if (resource_host()) {
139     resource_host()->host()->SendUnsolicitedReply(
140         resource_host()->pp_resource(), PpapiPluginMsg_VpnProvider_OnUnbind());
141   }
142 }
143 
OnBind(ppapi::host::HostMessageContext * context,const std::string & configuration_id,const std::string & configuration_name)144 int32_t PepperVpnProviderMessageFilter::OnBind(
145     ppapi::host::HostMessageContext* context,
146     const std::string& configuration_id,
147     const std::string& configuration_name) {
148   if (!vpn_service_proxy_)
149     return PP_ERROR_FAILED;
150   if (!content::GetContentClient()->browser()->IsPepperVpnProviderAPIAllowed(
151           browser_context_, document_url_)) {
152     LOG(ERROR) << "Host " << document_url_.host()
153                << " cannot use vpnProvider API";
154     return PP_ERROR_NOACCESS;
155   }
156 
157   configuration_id_ = configuration_id;
158   configuration_name_ = configuration_name;
159 
160   return DoBind(base::BindOnce(&PepperVpnProviderMessageFilter::OnBindSuccess,
161                                weak_factory_.GetWeakPtr(),
162                                context->MakeReplyMessageContext()),
163                 base::BindOnce(&PepperVpnProviderMessageFilter::OnBindFailure,
164                                weak_factory_.GetWeakPtr(),
165                                context->MakeReplyMessageContext()));
166 }
167 
OnSendPacket(ppapi::host::HostMessageContext * context,uint32_t packet_size,uint32_t id)168 int32_t PepperVpnProviderMessageFilter::OnSendPacket(
169     ppapi::host::HostMessageContext* context,
170     uint32_t packet_size,
171     uint32_t id) {
172   if (!vpn_service_proxy_)
173     return PP_ERROR_FAILED;
174   if (packet_size > kMaxPacketSize)
175     return PP_ERROR_MESSAGE_TOO_BIG;
176 
177   char* packet_pointer = static_cast<char*>(send_packet_buffer_->GetBuffer(id));
178   std::vector<char> packet(packet_pointer, packet_pointer + packet_size);
179 
180   return DoSendPacket(
181       packet,
182       base::BindOnce(&PepperVpnProviderMessageFilter::OnSendPacketSuccess,
183                      weak_factory_.GetWeakPtr(),
184                      context->MakeReplyMessageContext(), id),
185       base::BindOnce(&PepperVpnProviderMessageFilter::OnSendPacketFailure,
186                      weak_factory_.GetWeakPtr(),
187                      context->MakeReplyMessageContext(), id));
188 }
189 
OnPacketReceivedReply(ppapi::host::HostMessageContext * context,uint32_t id)190 int32_t PepperVpnProviderMessageFilter::OnPacketReceivedReply(
191     ppapi::host::HostMessageContext* context,
192     uint32_t id) {
193   if (!received_packets_.empty()) {
194     DoPacketReceived(received_packets_.front(), id);
195     received_packets_.pop();
196   } else {
197     recv_packet_buffer_->SetAvailable(id, true);
198   }
199 
200   return PP_OK;
201 }
202 
DoBind(SuccessCallback success_callback,FailureCallback failure_callback)203 int32_t PepperVpnProviderMessageFilter::DoBind(
204     SuccessCallback success_callback,
205     FailureCallback failure_callback) {
206   // Initialize shared memory
207   if (!send_packet_buffer_ || !recv_packet_buffer_) {
208     base::UnsafeSharedMemoryRegion send_buffer =
209         base::UnsafeSharedMemoryRegion::Create(kBufferSize);
210     base::UnsafeSharedMemoryRegion recv_buffer =
211         base::UnsafeSharedMemoryRegion::Create(kBufferSize);
212     if (!send_buffer.IsValid() || !recv_buffer.IsValid())
213       return PP_ERROR_NOMEMORY;
214 
215     base::WritableSharedMemoryMapping send_mapping = send_buffer.Map();
216     base::WritableSharedMemoryMapping recv_mapping = recv_buffer.Map();
217     if (!send_mapping.IsValid() || !recv_mapping.IsValid())
218       return PP_ERROR_NOMEMORY;
219 
220     send_packet_buffer_ = std::make_unique<ppapi::VpnProviderSharedBuffer>(
221         kMaxBufferedPackets, kMaxPacketSize, std::move(send_buffer),
222         std::move(send_mapping));
223     recv_packet_buffer_ = std::make_unique<ppapi::VpnProviderSharedBuffer>(
224         kMaxBufferedPackets, kMaxPacketSize, std::move(recv_buffer),
225         std::move(recv_mapping));
226   }
227 
228   vpn_service_proxy_->Bind(
229       document_url_.host(), configuration_id_, configuration_name_,
230       std::move(success_callback), std::move(failure_callback),
231       std::make_unique<PepperVpnProviderResourceHostProxyImpl>(
232           weak_factory_.GetWeakPtr()));
233 
234   return PP_OK_COMPLETIONPENDING;
235 }
236 
OnBindSuccess(const ppapi::host::ReplyMessageContext & context)237 void PepperVpnProviderMessageFilter::OnBindSuccess(
238     const ppapi::host::ReplyMessageContext& context) {
239   bound_ = true;
240 
241   context.params.AppendHandle(
242       ppapi::proxy::SerializedHandle(send_packet_buffer_->DuplicateRegion()));
243   context.params.AppendHandle(
244       ppapi::proxy::SerializedHandle(recv_packet_buffer_->DuplicateRegion()));
245 
246   OnBindReply(context, PP_OK);
247 }
248 
OnBindFailure(const ppapi::host::ReplyMessageContext & context,const std::string & error_name,const std::string & error_message)249 void PepperVpnProviderMessageFilter::OnBindFailure(
250     const ppapi::host::ReplyMessageContext& context,
251     const std::string& error_name,
252     const std::string& error_message) {
253   LOG(ERROR) << "PepperVpnProviderMessageFilter::OnBindFailure(): "
254              << "error_name: "
255              << "\"" << error_name << "\", "
256              << "error_message: "
257              << "\"" << error_message << "\"";
258 
259   // Clear buffers on error.
260   send_packet_buffer_.reset();
261   recv_packet_buffer_.reset();
262 
263   OnBindReply(context, PP_ERROR_FAILED);
264 }
265 
OnBindReply(const ppapi::host::ReplyMessageContext & context,int32_t reply)266 void PepperVpnProviderMessageFilter::OnBindReply(
267     const ppapi::host::ReplyMessageContext& context,
268     int32_t reply) {
269   SendReply(context, PpapiPluginMsg_VpnProvider_BindReply(
270                          kMaxBufferedPackets, kMaxPacketSize, reply));
271 }
272 
DoSendPacket(const std::vector<char> & packet,SuccessCallback success_callback,FailureCallback failure_callback)273 int32_t PepperVpnProviderMessageFilter::DoSendPacket(
274     const std::vector<char>& packet,
275     SuccessCallback success_callback,
276     FailureCallback failure_callback) {
277   vpn_service_proxy_->SendPacket(document_url_.host(), packet,
278                                  std::move(success_callback),
279                                  std::move(failure_callback));
280   return PP_OK_COMPLETIONPENDING;
281 }
282 
OnSendPacketSuccess(const ppapi::host::ReplyMessageContext & context,uint32_t id)283 void PepperVpnProviderMessageFilter::OnSendPacketSuccess(
284     const ppapi::host::ReplyMessageContext& context,
285     uint32_t id) {
286   OnSendPacketReply(context, id);
287 }
288 
OnSendPacketFailure(const ppapi::host::ReplyMessageContext & context,uint32_t id,const std::string & error_name,const std::string & error_message)289 void PepperVpnProviderMessageFilter::OnSendPacketFailure(
290     const ppapi::host::ReplyMessageContext& context,
291     uint32_t id,
292     const std::string& error_name,
293     const std::string& error_message) {
294   LOG(ERROR) << "PepperVpnProviderMessageFilter::OnSendPacketFailure(): "
295              << "error_name: "
296              << "\"" << error_name << "\", "
297              << "error_message: "
298              << "\"" << error_message << "\"";
299   OnSendPacketReply(context, id);
300 }
301 
OnSendPacketReply(const ppapi::host::ReplyMessageContext & context,uint32_t id)302 void PepperVpnProviderMessageFilter::OnSendPacketReply(
303     const ppapi::host::ReplyMessageContext& context,
304     uint32_t id) {
305   SendReply(context, PpapiPluginMsg_VpnProvider_SendPacketReply(id));
306 }
307 
DoPacketReceived(const std::vector<char> & packet,uint32_t id)308 void PepperVpnProviderMessageFilter::DoPacketReceived(
309     const std::vector<char>& packet,
310     uint32_t id) {
311   uint32_t packet_size = base::checked_cast<uint32_t>(packet.size());
312   DCHECK_GT(packet_size, 0U);
313 
314   const void* packet_pointer = &packet.front();
315   memcpy(recv_packet_buffer_->GetBuffer(id), packet_pointer, packet_size);
316 
317   if (resource_host()) {
318     resource_host()->host()->SendUnsolicitedReply(
319         resource_host()->pp_resource(),
320         PpapiPluginMsg_VpnProvider_OnPacketReceived(packet_size, id));
321   }
322 }
323 
324 }  // namespace content
325