Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / pepper / pepper_udp_socket_message_filter.cc
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_frame_id_(0) {
53   ++g_num_instances;
54   DCHECK(host);
55
56   if (!host->GetRenderFrameIDsForInstance(
57           instance, &render_process_id_, &render_frame_id_)) {
58     NOTREACHED();
59   }
60 }
61
62 PepperUDPSocketMessageFilter::~PepperUDPSocketMessageFilter() {
63   Close();
64   --g_num_instances;
65 }
66
67 // static
68 size_t PepperUDPSocketMessageFilter::GetNumInstances() {
69   return g_num_instances;
70 }
71
72 scoped_refptr<base::TaskRunner>
73 PepperUDPSocketMessageFilter::OverrideTaskRunnerForMessage(
74     const IPC::Message& message) {
75   switch (message.type()) {
76     case PpapiHostMsg_UDPSocket_SetOption::ID:
77     case PpapiHostMsg_UDPSocket_RecvFrom::ID:
78     case PpapiHostMsg_UDPSocket_Close::ID:
79       return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
80     case PpapiHostMsg_UDPSocket_Bind::ID:
81     case PpapiHostMsg_UDPSocket_SendTo::ID:
82       return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
83   }
84   return NULL;
85 }
86
87 int32_t PepperUDPSocketMessageFilter::OnResourceMessageReceived(
88     const IPC::Message& msg,
89     ppapi::host::HostMessageContext* context) {
90   IPC_BEGIN_MESSAGE_MAP(PepperUDPSocketMessageFilter, msg)
91   PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_SetOption,
92                                     OnMsgSetOption)
93   PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_Bind, OnMsgBind)
94   PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_RecvFrom,
95                                     OnMsgRecvFrom)
96   PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_SendTo, OnMsgSendTo)
97   PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_UDPSocket_Close, OnMsgClose)
98   IPC_END_MESSAGE_MAP()
99   return PP_ERROR_FAILED;
100 }
101
102 int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
103     const ppapi::host::HostMessageContext* context,
104     PP_UDPSocket_Option name,
105     const ppapi::SocketOptionData& value) {
106   DCHECK_CURRENTLY_ON(BrowserThread::IO);
107
108   if (closed_)
109     return PP_ERROR_FAILED;
110
111   switch (name) {
112     case PP_UDPSOCKET_OPTION_ADDRESS_REUSE:
113     case PP_UDPSOCKET_OPTION_BROADCAST: {
114       if (socket_.get()) {
115         // They only take effect before the socket is bound.
116         return PP_ERROR_FAILED;
117       }
118
119       bool boolean_value = false;
120       if (!value.GetBool(&boolean_value))
121         return PP_ERROR_BADARGUMENT;
122
123       if (name == PP_UDPSOCKET_OPTION_ADDRESS_REUSE)
124         allow_address_reuse_ = boolean_value;
125       else
126         allow_broadcast_ = boolean_value;
127       return PP_OK;
128     }
129     case PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE:
130     case PP_UDPSOCKET_OPTION_RECV_BUFFER_SIZE: {
131       if (!socket_.get()) {
132         // They only take effect after the socket is bound.
133         return PP_ERROR_FAILED;
134       }
135       int32_t integer_value = 0;
136       if (!value.GetInt32(&integer_value) || integer_value <= 0)
137         return PP_ERROR_BADARGUMENT;
138
139       int net_result = net::ERR_UNEXPECTED;
140       if (name == PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE) {
141         if (integer_value >
142             ppapi::proxy::UDPSocketResourceBase::kMaxSendBufferSize) {
143           return PP_ERROR_BADARGUMENT;
144         }
145         net_result = socket_->SetSendBufferSize(integer_value);
146       } else {
147         if (integer_value >
148             ppapi::proxy::UDPSocketResourceBase::kMaxReceiveBufferSize) {
149           return PP_ERROR_BADARGUMENT;
150         }
151         net_result = socket_->SetReceiveBufferSize(integer_value);
152       }
153       // TODO(wtc): Add error mapping code.
154       return (net_result == net::OK) ? PP_OK : PP_ERROR_FAILED;
155     }
156     default: {
157       NOTREACHED();
158       return PP_ERROR_BADARGUMENT;
159     }
160   }
161 }
162
163 int32_t PepperUDPSocketMessageFilter::OnMsgBind(
164     const ppapi::host::HostMessageContext* context,
165     const PP_NetAddress_Private& addr) {
166   DCHECK_CURRENTLY_ON(BrowserThread::UI);
167   DCHECK(context);
168
169   SocketPermissionRequest request =
170       pepper_socket_utils::CreateSocketPermissionRequest(
171           SocketPermissionRequest::UDP_BIND, addr);
172   if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_,
173                                              private_api_,
174                                              &request,
175                                              render_process_id_,
176                                              render_frame_id_)) {
177     return PP_ERROR_NOACCESS;
178   }
179
180   BrowserThread::PostTask(BrowserThread::IO,
181                           FROM_HERE,
182                           base::Bind(&PepperUDPSocketMessageFilter::DoBind,
183                                      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_CURRENTLY_ON(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_CURRENTLY_ON(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_,
239                                              private_api_,
240                                              &request,
241                                              render_process_id_,
242                                              render_frame_id_)) {
243     return PP_ERROR_NOACCESS;
244   }
245
246   BrowserThread::PostTask(BrowserThread::IO,
247                           FROM_HERE,
248                           base::Bind(&PepperUDPSocketMessageFilter::DoSendTo,
249                                      this,
250                                      context->MakeReplyMessageContext(),
251                                      data,
252                                      addr));
253   return PP_OK_COMPLETIONPENDING;
254 }
255
256 int32_t PepperUDPSocketMessageFilter::OnMsgClose(
257     const ppapi::host::HostMessageContext* context) {
258   DCHECK_CURRENTLY_ON(BrowserThread::IO);
259   Close();
260   return PP_OK;
261 }
262
263 void PepperUDPSocketMessageFilter::DoBind(
264     const ppapi::host::ReplyMessageContext& context,
265     const PP_NetAddress_Private& addr) {
266   DCHECK_CURRENTLY_ON(BrowserThread::IO);
267
268   if (closed_ || socket_.get()) {
269     SendBindError(context, PP_ERROR_FAILED);
270     return;
271   }
272
273   scoped_ptr<net::UDPServerSocket> socket(
274       new net::UDPServerSocket(NULL, net::NetLog::Source()));
275
276   net::IPAddressNumber address;
277   int port;
278   if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
279     SendBindError(context, PP_ERROR_ADDRESS_INVALID);
280     return;
281   }
282
283   if (allow_address_reuse_)
284     socket->AllowAddressReuse();
285   if (allow_broadcast_)
286     socket->AllowBroadcast();
287
288   int32_t pp_result =
289       NetErrorToPepperError(socket->Listen(net::IPEndPoint(address, port)));
290   if (pp_result != PP_OK) {
291     SendBindError(context, pp_result);
292     return;
293   }
294
295   net::IPEndPoint bound_address;
296   pp_result = NetErrorToPepperError(socket->GetLocalAddress(&bound_address));
297   if (pp_result != PP_OK) {
298     SendBindError(context, pp_result);
299     return;
300   }
301
302   PP_NetAddress_Private net_address = NetAddressPrivateImpl::kInvalidNetAddress;
303   if (!NetAddressPrivateImpl::IPEndPointToNetAddress(
304           bound_address.address(), bound_address.port(), &net_address)) {
305     SendBindError(context, PP_ERROR_ADDRESS_INVALID);
306     return;
307   }
308
309   allow_address_reuse_ = false;
310   allow_broadcast_ = false;
311   socket_.swap(socket);
312   SendBindReply(context, PP_OK, net_address);
313 }
314
315 void PepperUDPSocketMessageFilter::DoSendTo(
316     const ppapi::host::ReplyMessageContext& context,
317     const std::string& data,
318     const PP_NetAddress_Private& addr) {
319   DCHECK_CURRENTLY_ON(BrowserThread::IO);
320   DCHECK(socket_.get());
321
322   if (closed_ || !socket_.get()) {
323     SendSendToError(context, PP_ERROR_FAILED);
324     return;
325   }
326
327   if (sendto_buffer_.get()) {
328     SendSendToError(context, PP_ERROR_INPROGRESS);
329     return;
330   }
331
332   size_t num_bytes = data.size();
333   if (num_bytes == 0 ||
334       num_bytes > static_cast<size_t>(
335                       ppapi::proxy::UDPSocketResourceBase::kMaxWriteSize)) {
336     // Size of |data| is checked on the plugin side.
337     NOTREACHED();
338     SendSendToError(context, PP_ERROR_BADARGUMENT);
339     return;
340   }
341
342   sendto_buffer_ = new net::IOBufferWithSize(num_bytes);
343   memcpy(sendto_buffer_->data(), data.data(), num_bytes);
344
345   net::IPAddressNumber address;
346   int port;
347   if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
348     SendSendToError(context, PP_ERROR_ADDRESS_INVALID);
349     return;
350   }
351
352   // Please see OnMsgRecvFrom() for the reason why we use base::Unretained(this)
353   // when calling |socket_| methods.
354   int net_result = socket_->SendTo(
355       sendto_buffer_.get(),
356       sendto_buffer_->size(),
357       net::IPEndPoint(address, port),
358       base::Bind(&PepperUDPSocketMessageFilter::OnSendToCompleted,
359                  base::Unretained(this),
360                  context));
361   if (net_result != net::ERR_IO_PENDING)
362     OnSendToCompleted(context, net_result);
363 }
364
365 void PepperUDPSocketMessageFilter::Close() {
366   DCHECK_CURRENTLY_ON(BrowserThread::IO);
367   if (socket_.get() && !closed_)
368     socket_->Close();
369   closed_ = true;
370 }
371
372 void PepperUDPSocketMessageFilter::OnRecvFromCompleted(
373     const ppapi::host::ReplyMessageContext& context,
374     int net_result) {
375   DCHECK_CURRENTLY_ON(BrowserThread::IO);
376   DCHECK(recvfrom_buffer_.get());
377
378   int32_t pp_result = NetErrorToPepperError(net_result);
379
380   // Convert IPEndPoint we get back from RecvFrom to a PP_NetAddress_Private
381   // to send back.
382   PP_NetAddress_Private addr = NetAddressPrivateImpl::kInvalidNetAddress;
383   if (pp_result >= 0 &&
384       !NetAddressPrivateImpl::IPEndPointToNetAddress(
385           recvfrom_address_.address(), recvfrom_address_.port(), &addr)) {
386     pp_result = PP_ERROR_ADDRESS_INVALID;
387   }
388
389   if (pp_result >= 0) {
390     SendRecvFromReply(
391         context, PP_OK, std::string(recvfrom_buffer_->data(), pp_result), addr);
392   } else {
393     SendRecvFromError(context, pp_result);
394   }
395
396   recvfrom_buffer_ = NULL;
397 }
398
399 void PepperUDPSocketMessageFilter::OnSendToCompleted(
400     const ppapi::host::ReplyMessageContext& context,
401     int net_result) {
402   DCHECK_CURRENTLY_ON(BrowserThread::IO);
403   DCHECK(sendto_buffer_.get());
404
405   int32_t pp_result = NetErrorToPepperError(net_result);
406   if (pp_result < 0)
407     SendSendToError(context, pp_result);
408   else
409     SendSendToReply(context, PP_OK, pp_result);
410   sendto_buffer_ = NULL;
411 }
412
413 void PepperUDPSocketMessageFilter::SendBindReply(
414     const ppapi::host::ReplyMessageContext& context,
415     int32_t result,
416     const PP_NetAddress_Private& addr) {
417   ppapi::host::ReplyMessageContext reply_context(context);
418   reply_context.params.set_result(result);
419   SendReply(reply_context, PpapiPluginMsg_UDPSocket_BindReply(addr));
420 }
421
422 void PepperUDPSocketMessageFilter::SendRecvFromReply(
423     const ppapi::host::ReplyMessageContext& context,
424     int32_t result,
425     const std::string& data,
426     const PP_NetAddress_Private& addr) {
427   ppapi::host::ReplyMessageContext reply_context(context);
428   reply_context.params.set_result(result);
429   SendReply(reply_context, PpapiPluginMsg_UDPSocket_RecvFromReply(data, addr));
430 }
431
432 void PepperUDPSocketMessageFilter::SendSendToReply(
433     const ppapi::host::ReplyMessageContext& context,
434     int32_t result,
435     int32_t bytes_written) {
436   ppapi::host::ReplyMessageContext reply_context(context);
437   reply_context.params.set_result(result);
438   SendReply(reply_context, PpapiPluginMsg_UDPSocket_SendToReply(bytes_written));
439 }
440
441 void PepperUDPSocketMessageFilter::SendBindError(
442     const ppapi::host::ReplyMessageContext& context,
443     int32_t result) {
444   SendBindReply(context, result, NetAddressPrivateImpl::kInvalidNetAddress);
445 }
446
447 void PepperUDPSocketMessageFilter::SendRecvFromError(
448     const ppapi::host::ReplyMessageContext& context,
449     int32_t result) {
450   SendRecvFromReply(context,
451                     result,
452                     std::string(),
453                     NetAddressPrivateImpl::kInvalidNetAddress);
454 }
455
456 void PepperUDPSocketMessageFilter::SendSendToError(
457     const ppapi::host::ReplyMessageContext& context,
458     int32_t result) {
459   SendSendToReply(context, result, 0);
460 }
461
462 }  // namespace content