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