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.
5 #include "content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h"
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"
32 using ppapi::NetAddressPrivateImpl;
33 using ppapi::host::NetErrorToPepperError;
37 size_t g_num_instances = 0;
43 PepperUDPSocketMessageFilter::PepperUDPSocketMessageFilter(
44 BrowserPpapiHostImpl* host,
47 : allow_address_reuse_(false),
48 allow_broadcast_(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),
59 if (!host->GetRenderFrameIDsForInstance(
60 instance, &render_process_id_, &render_frame_id_)) {
65 PepperUDPSocketMessageFilter::~PepperUDPSocketMessageFilter() {
71 size_t PepperUDPSocketMessageFilter::GetNumInstances() {
72 return g_num_instances;
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);
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,
96 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_Bind, OnMsgBind)
97 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_SendTo,
99 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_UDPSocket_Close,
101 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
102 PpapiHostMsg_UDPSocket_RecvSlotAvailable, OnMsgRecvSlotAvailable)
103 PPAPI_END_MESSAGE_MAP()
104 return PP_ERROR_FAILED;
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);
114 return PP_ERROR_FAILED;
117 case PP_UDPSOCKET_OPTION_ADDRESS_REUSE:
118 case PP_UDPSOCKET_OPTION_BROADCAST: {
120 // They only take effect before the socket is bound.
121 return PP_ERROR_FAILED;
124 bool boolean_value = false;
125 if (!value.GetBool(&boolean_value))
126 return PP_ERROR_BADARGUMENT;
128 if (name == PP_UDPSOCKET_OPTION_ADDRESS_REUSE)
129 allow_address_reuse_ = boolean_value;
131 allow_broadcast_ = boolean_value;
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;
140 int32_t integer_value = 0;
141 if (!value.GetInt32(&integer_value) || integer_value <= 0)
142 return PP_ERROR_BADARGUMENT;
144 int net_result = net::ERR_UNEXPECTED;
145 if (name == PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE) {
147 ppapi::proxy::UDPSocketResourceBase::kMaxSendBufferSize) {
148 return PP_ERROR_BADARGUMENT;
150 net_result = socket_->SetSendBufferSize(integer_value);
153 ppapi::proxy::UDPSocketResourceBase::kMaxReceiveBufferSize) {
154 return PP_ERROR_BADARGUMENT;
156 net_result = socket_->SetReceiveBufferSize(integer_value);
158 // TODO(wtc): Add error mapping code.
159 return (net_result == net::OK) ? PP_OK : PP_ERROR_FAILED;
163 return PP_ERROR_BADARGUMENT;
168 int32_t PepperUDPSocketMessageFilter::OnMsgBind(
169 const ppapi::host::HostMessageContext* context,
170 const PP_NetAddress_Private& addr) {
171 DCHECK_CURRENTLY_ON(BrowserThread::UI);
174 SocketPermissionRequest request =
175 pepper_socket_utils::CreateSocketPermissionRequest(
176 SocketPermissionRequest::UDP_BIND, addr);
177 if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_,
182 return PP_ERROR_NOACCESS;
185 BrowserThread::PostTask(BrowserThread::IO,
187 base::Bind(&PepperUDPSocketMessageFilter::DoBind,
189 context->MakeReplyMessageContext(),
191 return PP_OK_COMPLETIONPENDING;
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);
201 SocketPermissionRequest request =
202 pepper_socket_utils::CreateSocketPermissionRequest(
203 SocketPermissionRequest::UDP_SEND_TO, addr);
204 if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_,
209 return PP_ERROR_NOACCESS;
212 BrowserThread::PostTask(BrowserThread::IO,
214 base::Bind(&PepperUDPSocketMessageFilter::DoSendTo,
216 context->MakeReplyMessageContext(),
219 return PP_OK_COMPLETIONPENDING;
222 int32_t PepperUDPSocketMessageFilter::OnMsgClose(
223 const ppapi::host::HostMessageContext* context) {
224 DCHECK_CURRENTLY_ON(BrowserThread::IO);
229 int32_t PepperUDPSocketMessageFilter::OnMsgRecvSlotAvailable(
230 const ppapi::host::HostMessageContext* context) {
231 DCHECK_CURRENTLY_ON(BrowserThread::IO);
233 if (remaining_recv_slots_ <
234 ppapi::proxy::UDPSocketResourceBase::kPluginReceiveBufferSlots) {
235 remaining_recv_slots_++;
238 if (!recvfrom_buffer_.get() && !closed_ && socket_.get()) {
239 DCHECK_EQ(1u, remaining_recv_slots_);
246 void PepperUDPSocketMessageFilter::DoBind(
247 const ppapi::host::ReplyMessageContext& context,
248 const PP_NetAddress_Private& addr) {
249 DCHECK_CURRENTLY_ON(BrowserThread::IO);
251 if (closed_ || socket_.get()) {
252 SendBindError(context, PP_ERROR_FAILED);
256 scoped_ptr<net::UDPServerSocket> socket(
257 new net::UDPServerSocket(NULL, net::NetLog::Source()));
259 net::IPAddressNumber address;
261 if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
262 SendBindError(context, PP_ERROR_ADDRESS_INVALID);
266 if (allow_address_reuse_)
267 socket->AllowAddressReuse();
268 if (allow_broadcast_)
269 socket->AllowBroadcast();
272 NetErrorToPepperError(socket->Listen(net::IPEndPoint(address, port)));
273 if (pp_result != PP_OK) {
274 SendBindError(context, pp_result);
278 net::IPEndPoint bound_address;
279 pp_result = NetErrorToPepperError(socket->GetLocalAddress(&bound_address));
280 if (pp_result != PP_OK) {
281 SendBindError(context, pp_result);
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);
292 allow_address_reuse_ = false;
293 allow_broadcast_ = false;
294 socket_.swap(socket);
295 SendBindReply(context, PP_OK, net_address);
300 void PepperUDPSocketMessageFilter::DoRecvFrom() {
301 DCHECK_CURRENTLY_ON(BrowserThread::IO);
303 DCHECK(socket_.get());
304 DCHECK(!recvfrom_buffer_.get());
305 DCHECK_GT(remaining_recv_slots_, 0u);
307 recvfrom_buffer_ = new net::IOBuffer(
308 ppapi::proxy::UDPSocketResourceBase::kMaxReadSize);
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
315 int net_result = socket_->RecvFrom(
316 recvfrom_buffer_.get(),
317 ppapi::proxy::UDPSocketResourceBase::kMaxReadSize,
319 base::Bind(&PepperUDPSocketMessageFilter::OnRecvFromCompleted,
320 base::Unretained(this)));
321 if (net_result != net::ERR_IO_PENDING)
322 OnRecvFromCompleted(net_result);
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());
332 if (closed_ || !socket_.get()) {
333 SendSendToError(context, PP_ERROR_FAILED);
337 if (sendto_buffer_.get()) {
338 SendSendToError(context, PP_ERROR_INPROGRESS);
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.
348 SendSendToError(context, PP_ERROR_BADARGUMENT);
352 sendto_buffer_ = new net::IOBufferWithSize(num_bytes);
353 memcpy(sendto_buffer_->data(), data.data(), num_bytes);
355 net::IPAddressNumber address;
357 if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
358 SendSendToError(context, PP_ERROR_ADDRESS_INVALID);
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),
371 if (net_result != net::ERR_IO_PENDING)
372 OnSendToCompleted(context, net_result);
375 void PepperUDPSocketMessageFilter::Close() {
376 DCHECK_CURRENTLY_ON(BrowserThread::IO);
377 if (socket_.get() && !closed_)
382 void PepperUDPSocketMessageFilter::OnRecvFromCompleted(int net_result) {
383 DCHECK_CURRENTLY_ON(BrowserThread::IO);
384 DCHECK(recvfrom_buffer_.get());
386 int32_t pp_result = NetErrorToPepperError(net_result);
388 // Convert IPEndPoint we get back from RecvFrom to a PP_NetAddress_Private
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;
397 if (pp_result >= 0) {
398 SendRecvFromResult(PP_OK, std::string(recvfrom_buffer_->data(), pp_result),
401 SendRecvFromError(pp_result);
404 recvfrom_buffer_ = NULL;
406 DCHECK_GT(remaining_recv_slots_, 0u);
407 remaining_recv_slots_--;
409 if (remaining_recv_slots_ > 0 && !closed_ && socket_.get())
413 void PepperUDPSocketMessageFilter::OnSendToCompleted(
414 const ppapi::host::ReplyMessageContext& context,
416 DCHECK_CURRENTLY_ON(BrowserThread::IO);
417 DCHECK(sendto_buffer_.get());
419 int32_t pp_result = NetErrorToPepperError(net_result);
421 SendSendToError(context, pp_result);
423 SendSendToReply(context, PP_OK, pp_result);
424 sendto_buffer_ = NULL;
427 void PepperUDPSocketMessageFilter::SendBindReply(
428 const ppapi::host::ReplyMessageContext& context,
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));
436 void PepperUDPSocketMessageFilter::SendRecvFromResult(
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));
445 void PepperUDPSocketMessageFilter::SendSendToReply(
446 const ppapi::host::ReplyMessageContext& context,
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));
454 void PepperUDPSocketMessageFilter::SendBindError(
455 const ppapi::host::ReplyMessageContext& context,
457 SendBindReply(context, result, NetAddressPrivateImpl::kInvalidNetAddress);
460 void PepperUDPSocketMessageFilter::SendRecvFromError(
462 SendRecvFromResult(result, std::string(),
463 NetAddressPrivateImpl::kInvalidNetAddress);
466 void PepperUDPSocketMessageFilter::SendSendToError(
467 const ppapi::host::ReplyMessageContext& context,
469 SendSendToReply(context, result, 0);
472 } // namespace content