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/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"
31 using ppapi::NetAddressPrivateImpl;
32 using ppapi::host::NetErrorToPepperError;
36 size_t g_num_instances = 0;
42 PepperUDPSocketMessageFilter::PepperUDPSocketMessageFilter(
43 BrowserPpapiHostImpl* host,
46 : allow_address_reuse_(false),
47 allow_broadcast_(false),
49 external_plugin_(host->external_plugin()),
50 private_api_(private_api),
51 render_process_id_(0),
56 if (!host->GetRenderFrameIDsForInstance(
57 instance, &render_process_id_, &render_frame_id_)) {
62 PepperUDPSocketMessageFilter::~PepperUDPSocketMessageFilter() {
68 size_t PepperUDPSocketMessageFilter::GetNumInstances() {
69 return g_num_instances;
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);
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,
93 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_Bind, OnMsgBind)
94 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_RecvFrom,
96 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_SendTo, OnMsgSendTo)
97 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_UDPSocket_Close, OnMsgClose)
99 return PP_ERROR_FAILED;
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);
109 return PP_ERROR_FAILED;
112 case PP_UDPSOCKET_OPTION_ADDRESS_REUSE:
113 case PP_UDPSOCKET_OPTION_BROADCAST: {
115 // They only take effect before the socket is bound.
116 return PP_ERROR_FAILED;
119 bool boolean_value = false;
120 if (!value.GetBool(&boolean_value))
121 return PP_ERROR_BADARGUMENT;
123 if (name == PP_UDPSOCKET_OPTION_ADDRESS_REUSE)
124 allow_address_reuse_ = boolean_value;
126 allow_broadcast_ = boolean_value;
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;
135 int32_t integer_value = 0;
136 if (!value.GetInt32(&integer_value) || integer_value <= 0)
137 return PP_ERROR_BADARGUMENT;
139 int net_result = net::ERR_UNEXPECTED;
140 if (name == PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE) {
142 ppapi::proxy::UDPSocketResourceBase::kMaxSendBufferSize) {
143 return PP_ERROR_BADARGUMENT;
145 net_result = socket_->SetSendBufferSize(integer_value);
148 ppapi::proxy::UDPSocketResourceBase::kMaxReceiveBufferSize) {
149 return PP_ERROR_BADARGUMENT;
151 net_result = socket_->SetReceiveBufferSize(integer_value);
153 // TODO(wtc): Add error mapping code.
154 return (net_result == net::OK) ? PP_OK : PP_ERROR_FAILED;
158 return PP_ERROR_BADARGUMENT;
163 int32_t PepperUDPSocketMessageFilter::OnMsgBind(
164 const ppapi::host::HostMessageContext* context,
165 const PP_NetAddress_Private& addr) {
166 DCHECK_CURRENTLY_ON(BrowserThread::UI);
169 SocketPermissionRequest request =
170 pepper_socket_utils::CreateSocketPermissionRequest(
171 SocketPermissionRequest::UDP_BIND, addr);
172 if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_,
177 return PP_ERROR_NOACCESS;
180 BrowserThread::PostTask(BrowserThread::IO,
182 base::Bind(&PepperUDPSocketMessageFilter::DoBind,
184 context->MakeReplyMessageContext(),
186 return PP_OK_COMPLETIONPENDING;
189 int32_t PepperUDPSocketMessageFilter::OnMsgRecvFrom(
190 const ppapi::host::HostMessageContext* context,
192 DCHECK_CURRENTLY_ON(BrowserThread::IO);
194 DCHECK(socket_.get());
196 if (closed_ || !socket_.get())
197 return PP_ERROR_FAILED;
199 if (recvfrom_buffer_.get())
200 return PP_ERROR_INPROGRESS;
202 if (num_bytes <= 0 ||
203 num_bytes > ppapi::proxy::UDPSocketResourceBase::kMaxReadSize) {
204 // |num_bytes| value is checked on the plugin side.
206 return PP_ERROR_BADARGUMENT;
209 recvfrom_buffer_ = new net::IOBuffer(num_bytes);
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
216 int net_result = socket_->RecvFrom(
217 recvfrom_buffer_.get(),
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;
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);
235 SocketPermissionRequest request =
236 pepper_socket_utils::CreateSocketPermissionRequest(
237 SocketPermissionRequest::UDP_SEND_TO, addr);
238 if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_,
243 return PP_ERROR_NOACCESS;
246 BrowserThread::PostTask(BrowserThread::IO,
248 base::Bind(&PepperUDPSocketMessageFilter::DoSendTo,
250 context->MakeReplyMessageContext(),
253 return PP_OK_COMPLETIONPENDING;
256 int32_t PepperUDPSocketMessageFilter::OnMsgClose(
257 const ppapi::host::HostMessageContext* context) {
258 DCHECK_CURRENTLY_ON(BrowserThread::IO);
263 void PepperUDPSocketMessageFilter::DoBind(
264 const ppapi::host::ReplyMessageContext& context,
265 const PP_NetAddress_Private& addr) {
266 DCHECK_CURRENTLY_ON(BrowserThread::IO);
268 if (closed_ || socket_.get()) {
269 SendBindError(context, PP_ERROR_FAILED);
273 scoped_ptr<net::UDPServerSocket> socket(
274 new net::UDPServerSocket(NULL, net::NetLog::Source()));
276 net::IPAddressNumber address;
278 if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
279 SendBindError(context, PP_ERROR_ADDRESS_INVALID);
283 if (allow_address_reuse_)
284 socket->AllowAddressReuse();
285 if (allow_broadcast_)
286 socket->AllowBroadcast();
289 NetErrorToPepperError(socket->Listen(net::IPEndPoint(address, port)));
290 if (pp_result != PP_OK) {
291 SendBindError(context, pp_result);
295 net::IPEndPoint bound_address;
296 pp_result = NetErrorToPepperError(socket->GetLocalAddress(&bound_address));
297 if (pp_result != PP_OK) {
298 SendBindError(context, pp_result);
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);
309 allow_address_reuse_ = false;
310 allow_broadcast_ = false;
311 socket_.swap(socket);
312 SendBindReply(context, PP_OK, net_address);
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());
322 if (closed_ || !socket_.get()) {
323 SendSendToError(context, PP_ERROR_FAILED);
327 if (sendto_buffer_.get()) {
328 SendSendToError(context, PP_ERROR_INPROGRESS);
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.
338 SendSendToError(context, PP_ERROR_BADARGUMENT);
342 sendto_buffer_ = new net::IOBufferWithSize(num_bytes);
343 memcpy(sendto_buffer_->data(), data.data(), num_bytes);
345 net::IPAddressNumber address;
347 if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
348 SendSendToError(context, PP_ERROR_ADDRESS_INVALID);
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),
361 if (net_result != net::ERR_IO_PENDING)
362 OnSendToCompleted(context, net_result);
365 void PepperUDPSocketMessageFilter::Close() {
366 DCHECK_CURRENTLY_ON(BrowserThread::IO);
367 if (socket_.get() && !closed_)
372 void PepperUDPSocketMessageFilter::OnRecvFromCompleted(
373 const ppapi::host::ReplyMessageContext& context,
375 DCHECK_CURRENTLY_ON(BrowserThread::IO);
376 DCHECK(recvfrom_buffer_.get());
378 int32_t pp_result = NetErrorToPepperError(net_result);
380 // Convert IPEndPoint we get back from RecvFrom to a PP_NetAddress_Private
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;
389 if (pp_result >= 0) {
391 context, PP_OK, std::string(recvfrom_buffer_->data(), pp_result), addr);
393 SendRecvFromError(context, pp_result);
396 recvfrom_buffer_ = NULL;
399 void PepperUDPSocketMessageFilter::OnSendToCompleted(
400 const ppapi::host::ReplyMessageContext& context,
402 DCHECK_CURRENTLY_ON(BrowserThread::IO);
403 DCHECK(sendto_buffer_.get());
405 int32_t pp_result = NetErrorToPepperError(net_result);
407 SendSendToError(context, pp_result);
409 SendSendToReply(context, PP_OK, pp_result);
410 sendto_buffer_ = NULL;
413 void PepperUDPSocketMessageFilter::SendBindReply(
414 const ppapi::host::ReplyMessageContext& context,
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));
422 void PepperUDPSocketMessageFilter::SendRecvFromReply(
423 const ppapi::host::ReplyMessageContext& context,
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));
432 void PepperUDPSocketMessageFilter::SendSendToReply(
433 const ppapi::host::ReplyMessageContext& context,
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));
441 void PepperUDPSocketMessageFilter::SendBindError(
442 const ppapi::host::ReplyMessageContext& context,
444 SendBindReply(context, result, NetAddressPrivateImpl::kInvalidNetAddress);
447 void PepperUDPSocketMessageFilter::SendRecvFromError(
448 const ppapi::host::ReplyMessageContext& context,
450 SendRecvFromReply(context,
453 NetAddressPrivateImpl::kInvalidNetAddress);
456 void PepperUDPSocketMessageFilter::SendSendToError(
457 const ppapi::host::ReplyMessageContext& context,
459 SendSendToReply(context, result, 0);
462 } // namespace content