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