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
31using ppapi::host::NetErrorToPepperError;
32using ppapi::NetAddressPrivateImpl;
33
34namespace {
35
36size_t g_num_instances = 0;
37
38}  // namespace
39
40namespace content {
41
42PepperUDPSocketMessageFilter::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
63PepperUDPSocketMessageFilter::~PepperUDPSocketMessageFilter() {
64  Close();
65  --g_num_instances;
66}
67
68// static
69size_t PepperUDPSocketMessageFilter::GetNumInstances() {
70  return g_num_instances;
71}
72
73scoped_refptr<base::TaskRunner>
74PepperUDPSocketMessageFilter::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
88int32_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
106int32_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
166int32_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
189int32_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
228int32_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
251int32_t PepperUDPSocketMessageFilter::OnMsgClose(
252    const ppapi::host::HostMessageContext* context) {
253  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
254  Close();
255  return PP_OK;
256}
257
258void 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
312void 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
362void PepperUDPSocketMessageFilter::Close() {
363  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
364  if (socket_.get() && !closed_)
365    socket_->Close();
366  closed_ = true;
367}
368
369void 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
396void 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
410void 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
419void 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
430void 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
440void PepperUDPSocketMessageFilter::SendBindError(
441    const ppapi::host::ReplyMessageContext& context,
442    int32_t result) {
443  SendBindReply(context, result, NetAddressPrivateImpl::kInvalidNetAddress);
444}
445
446void 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
455void PepperUDPSocketMessageFilter::SendSendToError(
456    const ppapi::host::ReplyMessageContext& context,
457    int32_t result) {
458  SendSendToReply(context, result, 0);
459}
460
461}  // namespace content
462