1// Copyright 2013 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_udp_socket_message_filter.h"
6
7#include <cstring>
8
9#include "base/compiler_specific.h"
10#include "base/logging.h"
11#include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
12#include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
13#include "content/public/browser/browser_thread.h"
14#include "content/public/common/process_type.h"
15#include "content/public/common/socket_permission_request.h"
16#include "ipc/ipc_message_macros.h"
17#include "net/base/io_buffer.h"
18#include "net/base/net_errors.h"
19#include "net/udp/udp_server_socket.h"
20#include "ppapi/c/pp_errors.h"
21#include "ppapi/c/private/ppb_net_address_private.h"
22#include "ppapi/host/dispatch_host_message.h"
23#include "ppapi/host/error_conversion.h"
24#include "ppapi/host/host_message_context.h"
25#include "ppapi/host/ppapi_host.h"
26#include "ppapi/host/resource_host.h"
27#include "ppapi/proxy/ppapi_messages.h"
28#include "ppapi/proxy/udp_socket_resource_base.h"
29#include "ppapi/shared_impl/private/net_address_private_impl.h"
30#include "ppapi/shared_impl/socket_option_data.h"
31
32using ppapi::NetAddressPrivateImpl;
33using ppapi::host::NetErrorToPepperError;
34
35namespace {
36
37size_t g_num_instances = 0;
38
39}  // namespace
40
41namespace content {
42
43PepperUDPSocketMessageFilter::PepperUDPSocketMessageFilter(
44    BrowserPpapiHostImpl* host,
45    PP_Instance instance,
46    bool private_api)
47    : allow_address_reuse_(false),
48      allow_broadcast_(false),
49      closed_(false),
50      remaining_recv_slots_(
51          ppapi::proxy::UDPSocketResourceBase::kPluginReceiveBufferSlots),
52      external_plugin_(host->external_plugin()),
53      private_api_(private_api),
54      render_process_id_(0),
55      render_frame_id_(0) {
56  ++g_num_instances;
57  DCHECK(host);
58
59  if (!host->GetRenderFrameIDsForInstance(
60          instance, &render_process_id_, &render_frame_id_)) {
61    NOTREACHED();
62  }
63}
64
65PepperUDPSocketMessageFilter::~PepperUDPSocketMessageFilter() {
66  Close();
67  --g_num_instances;
68}
69
70// static
71size_t PepperUDPSocketMessageFilter::GetNumInstances() {
72  return g_num_instances;
73}
74
75scoped_refptr<base::TaskRunner>
76PepperUDPSocketMessageFilter::OverrideTaskRunnerForMessage(
77    const IPC::Message& message) {
78  switch (message.type()) {
79    case PpapiHostMsg_UDPSocket_SetOption::ID:
80    case PpapiHostMsg_UDPSocket_Close::ID:
81    case PpapiHostMsg_UDPSocket_RecvSlotAvailable::ID:
82      return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
83    case PpapiHostMsg_UDPSocket_Bind::ID:
84    case PpapiHostMsg_UDPSocket_SendTo::ID:
85      return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
86  }
87  return NULL;
88}
89
90int32_t PepperUDPSocketMessageFilter::OnResourceMessageReceived(
91    const IPC::Message& msg,
92    ppapi::host::HostMessageContext* context) {
93  PPAPI_BEGIN_MESSAGE_MAP(PepperUDPSocketMessageFilter, msg)
94    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_SetOption,
95                                      OnMsgSetOption)
96    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_Bind, OnMsgBind)
97    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_SendTo,
98                                      OnMsgSendTo)
99    PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_UDPSocket_Close,
100                                        OnMsgClose)
101    PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
102        PpapiHostMsg_UDPSocket_RecvSlotAvailable, OnMsgRecvSlotAvailable)
103  PPAPI_END_MESSAGE_MAP()
104  return PP_ERROR_FAILED;
105}
106
107int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
108    const ppapi::host::HostMessageContext* context,
109    PP_UDPSocket_Option name,
110    const ppapi::SocketOptionData& value) {
111  DCHECK_CURRENTLY_ON(BrowserThread::IO);
112
113  if (closed_)
114    return PP_ERROR_FAILED;
115
116  switch (name) {
117    case PP_UDPSOCKET_OPTION_ADDRESS_REUSE:
118    case PP_UDPSOCKET_OPTION_BROADCAST: {
119      if (socket_.get()) {
120        // They only take effect before the socket is bound.
121        return PP_ERROR_FAILED;
122      }
123
124      bool boolean_value = false;
125      if (!value.GetBool(&boolean_value))
126        return PP_ERROR_BADARGUMENT;
127
128      if (name == PP_UDPSOCKET_OPTION_ADDRESS_REUSE)
129        allow_address_reuse_ = boolean_value;
130      else
131        allow_broadcast_ = boolean_value;
132      return PP_OK;
133    }
134    case PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE:
135    case PP_UDPSOCKET_OPTION_RECV_BUFFER_SIZE: {
136      if (!socket_.get()) {
137        // They only take effect after the socket is bound.
138        return PP_ERROR_FAILED;
139      }
140      int32_t integer_value = 0;
141      if (!value.GetInt32(&integer_value) || integer_value <= 0)
142        return PP_ERROR_BADARGUMENT;
143
144      int net_result = net::ERR_UNEXPECTED;
145      if (name == PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE) {
146        if (integer_value >
147            ppapi::proxy::UDPSocketResourceBase::kMaxSendBufferSize) {
148          return PP_ERROR_BADARGUMENT;
149        }
150        net_result = socket_->SetSendBufferSize(integer_value);
151      } else {
152        if (integer_value >
153            ppapi::proxy::UDPSocketResourceBase::kMaxReceiveBufferSize) {
154          return PP_ERROR_BADARGUMENT;
155        }
156        net_result = socket_->SetReceiveBufferSize(integer_value);
157      }
158      // TODO(wtc): Add error mapping code.
159      return (net_result == net::OK) ? PP_OK : PP_ERROR_FAILED;
160    }
161    default: {
162      NOTREACHED();
163      return PP_ERROR_BADARGUMENT;
164    }
165  }
166}
167
168int32_t PepperUDPSocketMessageFilter::OnMsgBind(
169    const ppapi::host::HostMessageContext* context,
170    const PP_NetAddress_Private& addr) {
171  DCHECK_CURRENTLY_ON(BrowserThread::UI);
172  DCHECK(context);
173
174  SocketPermissionRequest request =
175      pepper_socket_utils::CreateSocketPermissionRequest(
176          SocketPermissionRequest::UDP_BIND, addr);
177  if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_,
178                                             private_api_,
179                                             &request,
180                                             render_process_id_,
181                                             render_frame_id_)) {
182    return PP_ERROR_NOACCESS;
183  }
184
185  BrowserThread::PostTask(BrowserThread::IO,
186                          FROM_HERE,
187                          base::Bind(&PepperUDPSocketMessageFilter::DoBind,
188                                     this,
189                                     context->MakeReplyMessageContext(),
190                                     addr));
191  return PP_OK_COMPLETIONPENDING;
192}
193
194int32_t PepperUDPSocketMessageFilter::OnMsgSendTo(
195    const ppapi::host::HostMessageContext* context,
196    const std::string& data,
197    const PP_NetAddress_Private& addr) {
198  DCHECK_CURRENTLY_ON(BrowserThread::UI);
199  DCHECK(context);
200
201  SocketPermissionRequest request =
202      pepper_socket_utils::CreateSocketPermissionRequest(
203          SocketPermissionRequest::UDP_SEND_TO, addr);
204  if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_,
205                                             private_api_,
206                                             &request,
207                                             render_process_id_,
208                                             render_frame_id_)) {
209    return PP_ERROR_NOACCESS;
210  }
211
212  BrowserThread::PostTask(BrowserThread::IO,
213                          FROM_HERE,
214                          base::Bind(&PepperUDPSocketMessageFilter::DoSendTo,
215                                     this,
216                                     context->MakeReplyMessageContext(),
217                                     data,
218                                     addr));
219  return PP_OK_COMPLETIONPENDING;
220}
221
222int32_t PepperUDPSocketMessageFilter::OnMsgClose(
223    const ppapi::host::HostMessageContext* context) {
224  DCHECK_CURRENTLY_ON(BrowserThread::IO);
225  Close();
226  return PP_OK;
227}
228
229int32_t PepperUDPSocketMessageFilter::OnMsgRecvSlotAvailable(
230    const ppapi::host::HostMessageContext* context) {
231  DCHECK_CURRENTLY_ON(BrowserThread::IO);
232
233  if (remaining_recv_slots_ <
234          ppapi::proxy::UDPSocketResourceBase::kPluginReceiveBufferSlots) {
235    remaining_recv_slots_++;
236  }
237
238  if (!recvfrom_buffer_.get() && !closed_ && socket_.get()) {
239    DCHECK_EQ(1u, remaining_recv_slots_);
240    DoRecvFrom();
241  }
242
243  return PP_OK;
244}
245
246void PepperUDPSocketMessageFilter::DoBind(
247    const ppapi::host::ReplyMessageContext& context,
248    const PP_NetAddress_Private& addr) {
249  DCHECK_CURRENTLY_ON(BrowserThread::IO);
250
251  if (closed_ || socket_.get()) {
252    SendBindError(context, PP_ERROR_FAILED);
253    return;
254  }
255
256  scoped_ptr<net::UDPServerSocket> socket(
257      new net::UDPServerSocket(NULL, net::NetLog::Source()));
258
259  net::IPAddressNumber address;
260  int port;
261  if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
262    SendBindError(context, PP_ERROR_ADDRESS_INVALID);
263    return;
264  }
265
266  if (allow_address_reuse_)
267    socket->AllowAddressReuse();
268  if (allow_broadcast_)
269    socket->AllowBroadcast();
270
271  int32_t pp_result =
272      NetErrorToPepperError(socket->Listen(net::IPEndPoint(address, port)));
273  if (pp_result != PP_OK) {
274    SendBindError(context, pp_result);
275    return;
276  }
277
278  net::IPEndPoint bound_address;
279  pp_result = NetErrorToPepperError(socket->GetLocalAddress(&bound_address));
280  if (pp_result != PP_OK) {
281    SendBindError(context, pp_result);
282    return;
283  }
284
285  PP_NetAddress_Private net_address = NetAddressPrivateImpl::kInvalidNetAddress;
286  if (!NetAddressPrivateImpl::IPEndPointToNetAddress(
287          bound_address.address(), bound_address.port(), &net_address)) {
288    SendBindError(context, PP_ERROR_ADDRESS_INVALID);
289    return;
290  }
291
292  allow_address_reuse_ = false;
293  allow_broadcast_ = false;
294  socket_.swap(socket);
295  SendBindReply(context, PP_OK, net_address);
296
297  DoRecvFrom();
298}
299
300void PepperUDPSocketMessageFilter::DoRecvFrom() {
301  DCHECK_CURRENTLY_ON(BrowserThread::IO);
302  DCHECK(!closed_);
303  DCHECK(socket_.get());
304  DCHECK(!recvfrom_buffer_.get());
305  DCHECK_GT(remaining_recv_slots_, 0u);
306
307  recvfrom_buffer_ = new net::IOBuffer(
308      ppapi::proxy::UDPSocketResourceBase::kMaxReadSize);
309
310  // Use base::Unretained(this), so that the lifespan of this object doesn't
311  // have to last until the callback is called.
312  // It is safe to do so because |socket_| is owned by this object. If this
313  // object gets destroyed (and so does |socket_|), the callback won't be
314  // called.
315  int net_result = socket_->RecvFrom(
316      recvfrom_buffer_.get(),
317      ppapi::proxy::UDPSocketResourceBase::kMaxReadSize,
318      &recvfrom_address_,
319      base::Bind(&PepperUDPSocketMessageFilter::OnRecvFromCompleted,
320                 base::Unretained(this)));
321  if (net_result != net::ERR_IO_PENDING)
322    OnRecvFromCompleted(net_result);
323}
324
325void PepperUDPSocketMessageFilter::DoSendTo(
326    const ppapi::host::ReplyMessageContext& context,
327    const std::string& data,
328    const PP_NetAddress_Private& addr) {
329  DCHECK_CURRENTLY_ON(BrowserThread::IO);
330  DCHECK(socket_.get());
331
332  if (closed_ || !socket_.get()) {
333    SendSendToError(context, PP_ERROR_FAILED);
334    return;
335  }
336
337  if (sendto_buffer_.get()) {
338    SendSendToError(context, PP_ERROR_INPROGRESS);
339    return;
340  }
341
342  size_t num_bytes = data.size();
343  if (num_bytes == 0 ||
344      num_bytes > static_cast<size_t>(
345                      ppapi::proxy::UDPSocketResourceBase::kMaxWriteSize)) {
346    // Size of |data| is checked on the plugin side.
347    NOTREACHED();
348    SendSendToError(context, PP_ERROR_BADARGUMENT);
349    return;
350  }
351
352  sendto_buffer_ = new net::IOBufferWithSize(num_bytes);
353  memcpy(sendto_buffer_->data(), data.data(), num_bytes);
354
355  net::IPAddressNumber address;
356  int port;
357  if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
358    SendSendToError(context, PP_ERROR_ADDRESS_INVALID);
359    return;
360  }
361
362  // Please see OnMsgRecvFrom() for the reason why we use base::Unretained(this)
363  // when calling |socket_| methods.
364  int net_result = socket_->SendTo(
365      sendto_buffer_.get(),
366      sendto_buffer_->size(),
367      net::IPEndPoint(address, port),
368      base::Bind(&PepperUDPSocketMessageFilter::OnSendToCompleted,
369                 base::Unretained(this),
370                 context));
371  if (net_result != net::ERR_IO_PENDING)
372    OnSendToCompleted(context, net_result);
373}
374
375void PepperUDPSocketMessageFilter::Close() {
376  DCHECK_CURRENTLY_ON(BrowserThread::IO);
377  if (socket_.get() && !closed_)
378    socket_->Close();
379  closed_ = true;
380}
381
382void PepperUDPSocketMessageFilter::OnRecvFromCompleted(int net_result) {
383  DCHECK_CURRENTLY_ON(BrowserThread::IO);
384  DCHECK(recvfrom_buffer_.get());
385
386  int32_t pp_result = NetErrorToPepperError(net_result);
387
388  // Convert IPEndPoint we get back from RecvFrom to a PP_NetAddress_Private
389  // to send back.
390  PP_NetAddress_Private addr = NetAddressPrivateImpl::kInvalidNetAddress;
391  if (pp_result >= 0 &&
392      !NetAddressPrivateImpl::IPEndPointToNetAddress(
393          recvfrom_address_.address(), recvfrom_address_.port(), &addr)) {
394    pp_result = PP_ERROR_ADDRESS_INVALID;
395  }
396
397  if (pp_result >= 0) {
398    SendRecvFromResult(PP_OK, std::string(recvfrom_buffer_->data(), pp_result),
399                       addr);
400  } else {
401    SendRecvFromError(pp_result);
402  }
403
404  recvfrom_buffer_ = NULL;
405
406  DCHECK_GT(remaining_recv_slots_, 0u);
407  remaining_recv_slots_--;
408
409  if (remaining_recv_slots_ > 0 && !closed_ && socket_.get())
410    DoRecvFrom();
411}
412
413void PepperUDPSocketMessageFilter::OnSendToCompleted(
414    const ppapi::host::ReplyMessageContext& context,
415    int net_result) {
416  DCHECK_CURRENTLY_ON(BrowserThread::IO);
417  DCHECK(sendto_buffer_.get());
418
419  int32_t pp_result = NetErrorToPepperError(net_result);
420  if (pp_result < 0)
421    SendSendToError(context, pp_result);
422  else
423    SendSendToReply(context, PP_OK, pp_result);
424  sendto_buffer_ = NULL;
425}
426
427void PepperUDPSocketMessageFilter::SendBindReply(
428    const ppapi::host::ReplyMessageContext& context,
429    int32_t result,
430    const PP_NetAddress_Private& addr) {
431  ppapi::host::ReplyMessageContext reply_context(context);
432  reply_context.params.set_result(result);
433  SendReply(reply_context, PpapiPluginMsg_UDPSocket_BindReply(addr));
434}
435
436void PepperUDPSocketMessageFilter::SendRecvFromResult(
437    int32_t result,
438    const std::string& data,
439    const PP_NetAddress_Private& addr) {
440  if (resource_host()) {
441    resource_host()->host()->SendUnsolicitedReply(
442        resource_host()->pp_resource(),
443        PpapiPluginMsg_UDPSocket_PushRecvResult(result, data, addr));
444  }
445}
446
447void PepperUDPSocketMessageFilter::SendSendToReply(
448    const ppapi::host::ReplyMessageContext& context,
449    int32_t result,
450    int32_t bytes_written) {
451  ppapi::host::ReplyMessageContext reply_context(context);
452  reply_context.params.set_result(result);
453  SendReply(reply_context, PpapiPluginMsg_UDPSocket_SendToReply(bytes_written));
454}
455
456void PepperUDPSocketMessageFilter::SendBindError(
457    const ppapi::host::ReplyMessageContext& context,
458    int32_t result) {
459  SendBindReply(context, result, NetAddressPrivateImpl::kInvalidNetAddress);
460}
461
462void PepperUDPSocketMessageFilter::SendRecvFromError(
463    int32_t result) {
464  SendRecvFromResult(result, std::string(),
465                     NetAddressPrivateImpl::kInvalidNetAddress);
466}
467
468void PepperUDPSocketMessageFilter::SendSendToError(
469    const ppapi::host::ReplyMessageContext& context,
470    int32_t result) {
471  SendSendToReply(context, result, 0);
472}
473
474}  // namespace content
475