448599d23fb749305b612f60d0cd73e7bd093698
[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/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
32 using ppapi::NetAddressPrivateImpl;
33 using ppapi::host::NetErrorToPepperError;
34
35 namespace {
36
37 size_t g_num_instances = 0;
38
39 }  // namespace
40
41 namespace content {
42
43 PepperUDPSocketMessageFilter::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
65 PepperUDPSocketMessageFilter::~PepperUDPSocketMessageFilter() {
66   Close();
67   --g_num_instances;
68 }
69
70 // static
71 size_t PepperUDPSocketMessageFilter::GetNumInstances() {
72   return g_num_instances;
73 }
74
75 scoped_refptr<base::TaskRunner>
76 PepperUDPSocketMessageFilter::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
90 int32_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
107 int32_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
168 int32_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
194 int32_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
222 int32_t PepperUDPSocketMessageFilter::OnMsgClose(
223     const ppapi::host::HostMessageContext* context) {
224   DCHECK_CURRENTLY_ON(BrowserThread::IO);
225   Close();
226   return PP_OK;
227 }
228
229 int32_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
246 void 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
300 void 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
325 void 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
375 void PepperUDPSocketMessageFilter::Close() {
376   DCHECK_CURRENTLY_ON(BrowserThread::IO);
377   if (socket_.get() && !closed_)
378     socket_->Close();
379   closed_ = true;
380 }
381
382 void 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
413 void 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
427 void 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
436 void PepperUDPSocketMessageFilter::SendRecvFromResult(
437     int32_t result,
438     const std::string& data,
439     const PP_NetAddress_Private& addr) {
440   resource_host()->host()->SendUnsolicitedReply(
441       resource_host()->pp_resource(),
442       PpapiPluginMsg_UDPSocket_PushRecvResult(result, data, addr));
443 }
444
445 void PepperUDPSocketMessageFilter::SendSendToReply(
446     const ppapi::host::ReplyMessageContext& context,
447     int32_t result,
448     int32_t bytes_written) {
449   ppapi::host::ReplyMessageContext reply_context(context);
450   reply_context.params.set_result(result);
451   SendReply(reply_context, PpapiPluginMsg_UDPSocket_SendToReply(bytes_written));
452 }
453
454 void PepperUDPSocketMessageFilter::SendBindError(
455     const ppapi::host::ReplyMessageContext& context,
456     int32_t result) {
457   SendBindReply(context, result, NetAddressPrivateImpl::kInvalidNetAddress);
458 }
459
460 void PepperUDPSocketMessageFilter::SendRecvFromError(
461     int32_t result) {
462   SendRecvFromResult(result, std::string(),
463                      NetAddressPrivateImpl::kInvalidNetAddress);
464 }
465
466 void PepperUDPSocketMessageFilter::SendSendToError(
467     const ppapi::host::ReplyMessageContext& context,
468     int32_t result) {
469   SendSendToReply(context, result, 0);
470 }
471
472 }  // namespace content