| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ppapi/proxy/udp_socket_resource_base.h" | 5 #include "ppapi/proxy/udp_socket_resource_base.h" |
| 6 | 6 |
| 7 #include <algorithm> | |
| 8 #include <cstring> | 7 #include <cstring> |
| 9 | 8 |
| 10 #include "base/logging.h" | 9 #include "base/logging.h" |
| 11 #include "ppapi/c/pp_bool.h" | 10 #include "ppapi/c/pp_bool.h" |
| 12 #include "ppapi/c/pp_completion_callback.h" | |
| 13 #include "ppapi/c/pp_errors.h" | 11 #include "ppapi/c/pp_errors.h" |
| 14 #include "ppapi/proxy/error_conversion.h" | 12 #include "ppapi/proxy/error_conversion.h" |
| 15 #include "ppapi/proxy/plugin_globals.h" | 13 #include "ppapi/proxy/plugin_globals.h" |
| 16 #include "ppapi/proxy/ppapi_messages.h" | 14 #include "ppapi/proxy/ppapi_messages.h" |
| 17 #include "ppapi/shared_impl/socket_option_data.h" | 15 #include "ppapi/shared_impl/socket_option_data.h" |
| 18 #include "ppapi/thunk/enter.h" | 16 #include "ppapi/thunk/enter.h" |
| 19 #include "ppapi/thunk/resource_creation_api.h" | |
| 20 | 17 |
| 21 namespace ppapi { | 18 namespace ppapi { |
| 22 namespace proxy { | 19 namespace proxy { |
| 23 | 20 |
| 24 const int32_t UDPSocketResourceBase::kMaxReadSize = 128 * 1024; | |
| 25 const int32_t UDPSocketResourceBase::kMaxWriteSize = 128 * 1024; | 21 const int32_t UDPSocketResourceBase::kMaxWriteSize = 128 * 1024; |
| 26 const int32_t UDPSocketResourceBase::kMaxSendBufferSize = | 22 const int32_t UDPSocketResourceBase::kMaxSendBufferSize = |
| 27 1024 * UDPSocketResourceBase::kMaxWriteSize; | 23 1024 * UDPSocketResourceBase::kMaxWriteSize; |
| 28 const int32_t UDPSocketResourceBase::kMaxReceiveBufferSize = | |
| 29 1024 * UDPSocketResourceBase::kMaxReadSize; | |
| 30 const size_t UDPSocketResourceBase::kPluginReceiveBufferSlots = 32u; | |
| 31 const size_t UDPSocketResourceBase::kPluginSendBufferSlots = 8u; | 24 const size_t UDPSocketResourceBase::kPluginSendBufferSlots = 8u; |
| 32 | 25 |
| 26 namespace { |
| 27 |
| 28 void RunCallback(scoped_refptr<TrackedCallback> callback, |
| 29 int32_t pp_result, |
| 30 bool private_api) { |
| 31 callback->Run(ConvertNetworkAPIErrorForCompatibility(pp_result, private_api)); |
| 32 } |
| 33 |
| 34 void PostAbortIfNecessary(const scoped_refptr<TrackedCallback>& callback) { |
| 35 if (TrackedCallback::IsPending(callback)) |
| 36 callback->PostAbort(); |
| 37 } |
| 38 |
| 39 } // namespace |
| 40 |
| 33 UDPSocketResourceBase::UDPSocketResourceBase(Connection connection, | 41 UDPSocketResourceBase::UDPSocketResourceBase(Connection connection, |
| 34 PP_Instance instance, | 42 PP_Instance instance, |
| 35 bool private_api) | 43 bool private_api) |
| 36 : PluginResource(connection, instance), | 44 : PluginResource(connection, instance), |
| 37 private_api_(private_api), | 45 private_api_(private_api), |
| 38 bind_called_(false), | 46 bind_called_(false), |
| 39 bound_(false), | 47 bound_(false), |
| 40 closed_(false), | 48 closed_(false), |
| 41 read_buffer_(NULL), | 49 recv_filter_(PluginGlobals::Get()->udp_socket_filter()), |
| 42 bytes_to_read_(-1), | 50 bound_addr_() { |
| 43 recvfrom_addr_resource_(NULL) { | 51 recv_filter_->AddUDPResource( |
| 44 recvfrom_addr_.size = 0; | 52 pp_instance(), pp_resource(), private_api, |
| 45 memset(recvfrom_addr_.data, 0, | 53 base::Bind(&UDPSocketResourceBase::SlotBecameAvailable, pp_resource())); |
| 46 arraysize(recvfrom_addr_.data) * sizeof(*recvfrom_addr_.data)); | |
| 47 bound_addr_.size = 0; | |
| 48 memset(bound_addr_.data, 0, | |
| 49 arraysize(bound_addr_.data) * sizeof(*bound_addr_.data)); | |
| 50 | |
| 51 if (private_api) | 54 if (private_api) |
| 52 SendCreate(BROWSER, PpapiHostMsg_UDPSocket_CreatePrivate()); | 55 SendCreate(BROWSER, PpapiHostMsg_UDPSocket_CreatePrivate()); |
| 53 else | 56 else |
| 54 SendCreate(BROWSER, PpapiHostMsg_UDPSocket_Create()); | 57 SendCreate(BROWSER, PpapiHostMsg_UDPSocket_Create()); |
| 55 | |
| 56 PluginGlobals::Get()->resource_reply_thread_registrar()->HandleOnIOThread( | |
| 57 PpapiPluginMsg_UDPSocket_PushRecvResult::ID); | |
| 58 } | 58 } |
| 59 | 59 |
| 60 UDPSocketResourceBase::~UDPSocketResourceBase() { | 60 UDPSocketResourceBase::~UDPSocketResourceBase() { |
| 61 CloseImpl(); |
| 61 } | 62 } |
| 62 | 63 |
| 63 int32_t UDPSocketResourceBase::SetOptionImpl( | 64 int32_t UDPSocketResourceBase::SetOptionImpl( |
| 64 PP_UDPSocket_Option name, | 65 PP_UDPSocket_Option name, |
| 65 const PP_Var& value, | 66 const PP_Var& value, |
| 66 bool check_bind_state, | 67 bool check_bind_state, |
| 67 scoped_refptr<TrackedCallback> callback) { | 68 scoped_refptr<TrackedCallback> callback) { |
| 68 if (closed_) | 69 if (closed_) |
| 69 return PP_ERROR_FAILED; | 70 return PP_ERROR_FAILED; |
| 70 | 71 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 PP_Bool UDPSocketResourceBase::GetBoundAddressImpl( | 159 PP_Bool UDPSocketResourceBase::GetBoundAddressImpl( |
| 159 PP_NetAddress_Private* addr) { | 160 PP_NetAddress_Private* addr) { |
| 160 if (!addr || !bound_ || closed_) | 161 if (!addr || !bound_ || closed_) |
| 161 return PP_FALSE; | 162 return PP_FALSE; |
| 162 | 163 |
| 163 *addr = bound_addr_; | 164 *addr = bound_addr_; |
| 164 return PP_TRUE; | 165 return PP_TRUE; |
| 165 } | 166 } |
| 166 | 167 |
| 167 int32_t UDPSocketResourceBase::RecvFromImpl( | 168 int32_t UDPSocketResourceBase::RecvFromImpl( |
| 168 char* buffer, | 169 char* buffer_out, |
| 169 int32_t num_bytes, | 170 int32_t num_bytes, |
| 170 PP_Resource* addr, | 171 PP_Resource* addr, |
| 171 scoped_refptr<TrackedCallback> callback) { | 172 scoped_refptr<TrackedCallback> callback) { |
| 172 if (!buffer || num_bytes <= 0) | 173 return recv_filter_->RequestData(pp_resource(), num_bytes, buffer_out, addr, |
| 173 return PP_ERROR_BADARGUMENT; | 174 callback); |
| 174 if (!bound_) | |
| 175 return PP_ERROR_FAILED; | |
| 176 if (TrackedCallback::IsPending(recvfrom_callback_)) | |
| 177 return PP_ERROR_INPROGRESS; | |
| 178 | |
| 179 if (recv_buffers_.empty()) { | |
| 180 read_buffer_ = buffer; | |
| 181 bytes_to_read_ = std::min(num_bytes, kMaxReadSize); | |
| 182 recvfrom_addr_resource_ = addr; | |
| 183 recvfrom_callback_ = callback; | |
| 184 | |
| 185 return PP_OK_COMPLETIONPENDING; | |
| 186 } else { | |
| 187 RecvBuffer& front = recv_buffers_.front(); | |
| 188 | |
| 189 if (num_bytes < static_cast<int32_t>(front.data.size())) | |
| 190 return PP_ERROR_MESSAGE_TOO_BIG; | |
| 191 | |
| 192 int32_t result = SetRecvFromOutput(front.result, front.data, front.addr, | |
| 193 buffer, num_bytes, addr); | |
| 194 | |
| 195 recv_buffers_.pop(); | |
| 196 Post(BROWSER, PpapiHostMsg_UDPSocket_RecvSlotAvailable()); | |
| 197 | |
| 198 return result; | |
| 199 } | |
| 200 } | 175 } |
| 201 | 176 |
| 202 PP_Bool UDPSocketResourceBase::GetRecvFromAddressImpl( | 177 PP_Bool UDPSocketResourceBase::GetRecvFromAddressImpl( |
| 203 PP_NetAddress_Private* addr) { | 178 PP_NetAddress_Private* addr) { |
| 204 if (!addr) | 179 if (!addr) |
| 205 return PP_FALSE; | 180 return PP_FALSE; |
| 206 *addr = recvfrom_addr_; | 181 *addr = recv_filter_->GetLastAddrPrivate(pp_resource()); |
| 207 return PP_TRUE; | 182 return PP_TRUE; |
| 208 } | 183 } |
| 209 | 184 |
| 210 int32_t UDPSocketResourceBase::SendToImpl( | 185 int32_t UDPSocketResourceBase::SendToImpl( |
| 211 const char* buffer, | 186 const char* buffer, |
| 212 int32_t num_bytes, | 187 int32_t num_bytes, |
| 213 const PP_NetAddress_Private* addr, | 188 const PP_NetAddress_Private* addr, |
| 214 scoped_refptr<TrackedCallback> callback) { | 189 scoped_refptr<TrackedCallback> callback) { |
| 215 if (!buffer || num_bytes <= 0 || !addr) | 190 if (!buffer || num_bytes <= 0 || !addr) |
| 216 return PP_ERROR_BADARGUMENT; | 191 return PP_ERROR_BADARGUMENT; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 236 | 211 |
| 237 void UDPSocketResourceBase::CloseImpl() { | 212 void UDPSocketResourceBase::CloseImpl() { |
| 238 if(closed_) | 213 if(closed_) |
| 239 return; | 214 return; |
| 240 | 215 |
| 241 bound_ = false; | 216 bound_ = false; |
| 242 closed_ = true; | 217 closed_ = true; |
| 243 | 218 |
| 244 Post(BROWSER, PpapiHostMsg_UDPSocket_Close()); | 219 Post(BROWSER, PpapiHostMsg_UDPSocket_Close()); |
| 245 | 220 |
| 246 PostAbortIfNecessary(&bind_callback_); | 221 PostAbortIfNecessary(bind_callback_); |
| 247 PostAbortIfNecessary(&recvfrom_callback_); | |
| 248 while (!sendto_callbacks_.empty()) { | 222 while (!sendto_callbacks_.empty()) { |
| 249 scoped_refptr<TrackedCallback> callback = sendto_callbacks_.front(); | 223 scoped_refptr<TrackedCallback> callback = sendto_callbacks_.front(); |
| 250 sendto_callbacks_.pop(); | 224 sendto_callbacks_.pop(); |
| 251 PostAbortIfNecessary(&callback); | 225 PostAbortIfNecessary(callback); |
| 252 } | 226 } |
| 253 | 227 recv_filter_->RemoveUDPResource(pp_resource()); |
| 254 read_buffer_ = NULL; | |
| 255 bytes_to_read_ = -1; | |
| 256 } | 228 } |
| 257 | 229 |
| 258 int32_t UDPSocketResourceBase::JoinGroupImpl( | 230 int32_t UDPSocketResourceBase::JoinGroupImpl( |
| 259 const PP_NetAddress_Private *group, | 231 const PP_NetAddress_Private *group, |
| 260 scoped_refptr<TrackedCallback> callback) { | 232 scoped_refptr<TrackedCallback> callback) { |
| 261 DCHECK(group); | 233 DCHECK(group); |
| 262 | 234 |
| 263 Call<PpapiPluginMsg_UDPSocket_JoinGroupReply>( | 235 Call<PpapiPluginMsg_UDPSocket_JoinGroupReply>( |
| 264 BROWSER, | 236 BROWSER, |
| 265 PpapiHostMsg_UDPSocket_JoinGroup(*group), | 237 PpapiHostMsg_UDPSocket_JoinGroup(*group), |
| (...skipping 12 matching lines...) Expand all Loading... |
| 278 Call<PpapiPluginMsg_UDPSocket_LeaveGroupReply>( | 250 Call<PpapiPluginMsg_UDPSocket_LeaveGroupReply>( |
| 279 BROWSER, | 251 BROWSER, |
| 280 PpapiHostMsg_UDPSocket_LeaveGroup(*group), | 252 PpapiHostMsg_UDPSocket_LeaveGroup(*group), |
| 281 base::Bind(&UDPSocketResourceBase::OnPluginMsgGeneralReply, | 253 base::Bind(&UDPSocketResourceBase::OnPluginMsgGeneralReply, |
| 282 base::Unretained(this), | 254 base::Unretained(this), |
| 283 callback), | 255 callback), |
| 284 callback); | 256 callback); |
| 285 return PP_OK_COMPLETIONPENDING; | 257 return PP_OK_COMPLETIONPENDING; |
| 286 } | 258 } |
| 287 | 259 |
| 288 void UDPSocketResourceBase::OnReplyReceived( | |
| 289 const ResourceMessageReplyParams& params, | |
| 290 const IPC::Message& msg) { | |
| 291 PPAPI_BEGIN_MESSAGE_MAP(UDPSocketResourceBase, msg) | |
| 292 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( | |
| 293 PpapiPluginMsg_UDPSocket_PushRecvResult, | |
| 294 OnPluginMsgPushRecvResult) | |
| 295 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED( | |
| 296 PluginResource::OnReplyReceived(params, msg)) | |
| 297 PPAPI_END_MESSAGE_MAP() | |
| 298 } | |
| 299 | |
| 300 void UDPSocketResourceBase::PostAbortIfNecessary( | |
| 301 scoped_refptr<TrackedCallback>* callback) { | |
| 302 if (TrackedCallback::IsPending(*callback)) | |
| 303 (*callback)->PostAbort(); | |
| 304 } | |
| 305 | |
| 306 void UDPSocketResourceBase::OnPluginMsgGeneralReply( | 260 void UDPSocketResourceBase::OnPluginMsgGeneralReply( |
| 307 scoped_refptr<TrackedCallback> callback, | 261 scoped_refptr<TrackedCallback> callback, |
| 308 const ResourceMessageReplyParams& params) { | 262 const ResourceMessageReplyParams& params) { |
| 309 if (TrackedCallback::IsPending(callback)) | 263 if (TrackedCallback::IsPending(callback)) |
| 310 RunCallback(callback, params.result()); | 264 RunCallback(callback, params.result(), private_api_); |
| 311 } | 265 } |
| 312 | 266 |
| 313 void UDPSocketResourceBase::OnPluginMsgBindReply( | 267 void UDPSocketResourceBase::OnPluginMsgBindReply( |
| 314 const ResourceMessageReplyParams& params, | 268 const ResourceMessageReplyParams& params, |
| 315 const PP_NetAddress_Private& bound_addr) { | 269 const PP_NetAddress_Private& bound_addr) { |
| 316 // It is possible that |bind_callback_| is pending while |closed_| is true: | 270 // It is possible that |bind_callback_| is pending while |closed_| is true: |
| 317 // CloseImpl() has been called, but a BindReply came earlier than the task to | 271 // CloseImpl() has been called, but a BindReply came earlier than the task to |
| 318 // abort |bind_callback_|. We don't want to update |bound_| or |bound_addr_| | 272 // abort |bind_callback_|. We don't want to update |bound_| or |bound_addr_| |
| 319 // in that case. | 273 // in that case. |
| 320 if (!TrackedCallback::IsPending(bind_callback_) || closed_) | 274 if (!TrackedCallback::IsPending(bind_callback_) || closed_) |
| 321 return; | 275 return; |
| 322 | 276 |
| 323 if (params.result() == PP_OK) | 277 if (params.result() == PP_OK) |
| 324 bound_ = true; | 278 bound_ = true; |
| 325 bound_addr_ = bound_addr; | 279 bound_addr_ = bound_addr; |
| 326 RunCallback(bind_callback_, params.result()); | 280 RunCallback(bind_callback_, params.result(), private_api_); |
| 327 } | |
| 328 | |
| 329 void UDPSocketResourceBase::OnPluginMsgPushRecvResult( | |
| 330 const ResourceMessageReplyParams& params, | |
| 331 int32_t result, | |
| 332 const std::string& data, | |
| 333 const PP_NetAddress_Private& addr) { | |
| 334 // TODO(yzshen): Support passing in a non-const string ref, so that we can | |
| 335 // eliminate one copy when storing the data in the buffer. | |
| 336 | |
| 337 DCHECK_LT(recv_buffers_.size(), kPluginReceiveBufferSlots); | |
| 338 | |
| 339 if (!TrackedCallback::IsPending(recvfrom_callback_) || !read_buffer_) { | |
| 340 recv_buffers_.push(RecvBuffer()); | |
| 341 RecvBuffer& back = recv_buffers_.back(); | |
| 342 back.result = result; | |
| 343 back.data = data; | |
| 344 back.addr = addr; | |
| 345 | |
| 346 return; | |
| 347 } | |
| 348 | |
| 349 DCHECK_EQ(recv_buffers_.size(), 0u); | |
| 350 | |
| 351 if (bytes_to_read_ < static_cast<int32_t>(data.size())) { | |
| 352 recv_buffers_.push(RecvBuffer()); | |
| 353 RecvBuffer& back = recv_buffers_.back(); | |
| 354 back.result = result; | |
| 355 back.data = data; | |
| 356 back.addr = addr; | |
| 357 | |
| 358 result = PP_ERROR_MESSAGE_TOO_BIG; | |
| 359 } else { | |
| 360 result = SetRecvFromOutput(result, data, addr, read_buffer_, bytes_to_read_, | |
| 361 recvfrom_addr_resource_); | |
| 362 Post(BROWSER, PpapiHostMsg_UDPSocket_RecvSlotAvailable()); | |
| 363 } | |
| 364 | |
| 365 read_buffer_ = NULL; | |
| 366 bytes_to_read_ = -1; | |
| 367 recvfrom_addr_resource_ = NULL; | |
| 368 | |
| 369 RunCallback(recvfrom_callback_, result); | |
| 370 } | 281 } |
| 371 | 282 |
| 372 void UDPSocketResourceBase::OnPluginMsgSendToReply( | 283 void UDPSocketResourceBase::OnPluginMsgSendToReply( |
| 373 const ResourceMessageReplyParams& params, | 284 const ResourceMessageReplyParams& params, |
| 374 int32_t bytes_written) { | 285 int32_t bytes_written) { |
| 375 // This can be empty if the socket was closed, but there are still tasks | 286 // This can be empty if the socket was closed, but there are still tasks |
| 376 // to be posted for this resource. | 287 // to be posted for this resource. |
| 377 if (sendto_callbacks_.empty()) | 288 if (sendto_callbacks_.empty()) |
| 378 return; | 289 return; |
| 379 | 290 |
| 380 scoped_refptr<TrackedCallback> callback = sendto_callbacks_.front(); | 291 scoped_refptr<TrackedCallback> callback = sendto_callbacks_.front(); |
| 381 sendto_callbacks_.pop(); | 292 sendto_callbacks_.pop(); |
| 382 if (!TrackedCallback::IsPending(callback)) | 293 if (!TrackedCallback::IsPending(callback)) |
| 383 return; | 294 return; |
| 384 | 295 |
| 385 if (params.result() == PP_OK) | 296 if (params.result() == PP_OK) |
| 386 RunCallback(callback, bytes_written); | 297 RunCallback(callback, bytes_written, private_api_); |
| 387 else | 298 else |
| 388 RunCallback(callback, params.result()); | 299 RunCallback(callback, params.result(), private_api_); |
| 389 } | 300 } |
| 390 | 301 |
| 391 void UDPSocketResourceBase::RunCallback(scoped_refptr<TrackedCallback> callback, | 302 // static |
| 392 int32_t pp_result) { | 303 void UDPSocketResourceBase::SlotBecameAvailable(PP_Resource resource) { |
| 393 callback->Run(ConvertNetworkAPIErrorForCompatibility(pp_result, | 304 PluginGlobals* globals = PluginGlobals::Get(); |
| 394 private_api_)); | 305 if (globals->ipc_task_runner()->RunsTasksOnCurrentThread()) { |
| 306 // We were invoked on the IO thread, so we do *not* have the ProxyLock and |
| 307 // we have to post over to the main thread in order to get the resource and |
| 308 // send the message. |
| 309 // TODO(dmichael): This is kind of stupid; we ought to be able to build up |
| 310 // the right message and send it directly from the IO thread. Unfortunately, |
| 311 // we need to get a sequence number, which right now requires the ProxyLock. |
| 312 if (globals->GetMainThreadMessageLoop()) { |
| 313 globals->GetMainThreadMessageLoop()->PostTask(FROM_HERE, |
| 314 RunWhileLocked(base::Bind( |
| 315 &UDPSocketResourceBase::SlotBecameAvailableWithLock, resource))); |
| 316 } |
| 317 } else { |
| 318 SlotBecameAvailableWithLock(resource); |
| 319 } |
| 395 } | 320 } |
| 396 | 321 |
| 397 int32_t UDPSocketResourceBase::SetRecvFromOutput( | 322 // static |
| 398 int32_t browser_result, | 323 void UDPSocketResourceBase::SlotBecameAvailableWithLock(PP_Resource resource) { |
| 399 const std::string& data, | 324 ProxyLock::AssertAcquired(); |
| 400 const PP_NetAddress_Private& addr, | 325 thunk::EnterResourceNoLock<thunk::PPB_UDPSocket_API> enter(resource, false); |
| 401 char* output_buffer, | 326 if (enter.failed()) |
| 402 int32_t num_bytes, | 327 return; |
| 403 PP_Resource* output_addr) { | 328 auto thiz(static_cast<UDPSocketResourceBase*>(enter.resource())); |
| 404 DCHECK_GE(num_bytes, static_cast<int32_t>(data.size())); | |
| 405 | 329 |
| 406 int32_t result = browser_result; | 330 if (!thiz->closed_) |
| 407 if (result == PP_OK && output_addr) { | 331 thiz->Post(BROWSER, PpapiHostMsg_UDPSocket_RecvSlotAvailable()); |
| 408 thunk::EnterResourceCreationNoLock enter(pp_instance()); | |
| 409 if (enter.succeeded()) { | |
| 410 *output_addr = enter.functions()->CreateNetAddressFromNetAddressPrivate( | |
| 411 pp_instance(), addr); | |
| 412 } else { | |
| 413 result = PP_ERROR_FAILED; | |
| 414 } | |
| 415 } | |
| 416 | |
| 417 if (result == PP_OK && !data.empty()) | |
| 418 memcpy(output_buffer, data.c_str(), data.size()); | |
| 419 | |
| 420 recvfrom_addr_ = addr; | |
| 421 | |
| 422 return result == PP_OK ? static_cast<int32_t>(data.size()) : result; | |
| 423 } | 332 } |
| 424 | 333 |
| 425 } // namespace proxy | 334 } // namespace proxy |
| 426 } // namespace ppapi | 335 } // namespace ppapi |
| OLD | NEW |