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