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 PP_ERROR_BADARGUMENT; | |
174 if (!bound_) | 173 if (!bound_) |
175 return PP_ERROR_FAILED; | 174 return PP_ERROR_FAILED; |
176 if (TrackedCallback::IsPending(recvfrom_callback_)) | 175 return recv_filter_->RequestData(pp_resource(), num_bytes, buffer_out, addr, |
177 return PP_ERROR_INPROGRESS; | 176 callback); |
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 } | 177 } |
201 | 178 |
202 PP_Bool UDPSocketResourceBase::GetRecvFromAddressImpl( | 179 PP_Bool UDPSocketResourceBase::GetRecvFromAddressImpl( |
203 PP_NetAddress_Private* addr) { | 180 PP_NetAddress_Private* addr) { |
204 if (!addr) | 181 if (!addr) |
205 return PP_FALSE; | 182 return PP_FALSE; |
206 *addr = recvfrom_addr_; | 183 *addr = recv_filter_->GetLastAddrPrivate(pp_resource()); |
207 return PP_TRUE; | 184 return PP_TRUE; |
208 } | 185 } |
209 | 186 |
210 int32_t UDPSocketResourceBase::SendToImpl( | 187 int32_t UDPSocketResourceBase::SendToImpl( |
211 const char* buffer, | 188 const char* buffer, |
212 int32_t num_bytes, | 189 int32_t num_bytes, |
213 const PP_NetAddress_Private* addr, | 190 const PP_NetAddress_Private* addr, |
214 scoped_refptr<TrackedCallback> callback) { | 191 scoped_refptr<TrackedCallback> callback) { |
215 if (!buffer || num_bytes <= 0 || !addr) | 192 if (!buffer || num_bytes <= 0 || !addr) |
216 return PP_ERROR_BADARGUMENT; | 193 return PP_ERROR_BADARGUMENT; |
(...skipping 19 matching lines...) Expand all Loading... |
236 | 213 |
237 void UDPSocketResourceBase::CloseImpl() { | 214 void UDPSocketResourceBase::CloseImpl() { |
238 if(closed_) | 215 if(closed_) |
239 return; | 216 return; |
240 | 217 |
241 bound_ = false; | 218 bound_ = false; |
242 closed_ = true; | 219 closed_ = true; |
243 | 220 |
244 Post(BROWSER, PpapiHostMsg_UDPSocket_Close()); | 221 Post(BROWSER, PpapiHostMsg_UDPSocket_Close()); |
245 | 222 |
246 PostAbortIfNecessary(&bind_callback_); | 223 PostAbortIfNecessary(bind_callback_); |
247 PostAbortIfNecessary(&recvfrom_callback_); | |
248 while (!sendto_callbacks_.empty()) { | 224 while (!sendto_callbacks_.empty()) { |
249 scoped_refptr<TrackedCallback> callback = sendto_callbacks_.front(); | 225 scoped_refptr<TrackedCallback> callback = sendto_callbacks_.front(); |
250 sendto_callbacks_.pop(); | 226 sendto_callbacks_.pop(); |
251 PostAbortIfNecessary(&callback); | 227 PostAbortIfNecessary(callback); |
252 } | 228 } |
253 | 229 recv_filter_->RemoveUDPResource(pp_resource()); |
254 read_buffer_ = NULL; | |
255 bytes_to_read_ = -1; | |
256 } | 230 } |
257 | 231 |
258 int32_t UDPSocketResourceBase::JoinGroupImpl( | 232 int32_t UDPSocketResourceBase::JoinGroupImpl( |
259 const PP_NetAddress_Private *group, | 233 const PP_NetAddress_Private *group, |
260 scoped_refptr<TrackedCallback> callback) { | 234 scoped_refptr<TrackedCallback> callback) { |
261 DCHECK(group); | 235 DCHECK(group); |
262 | 236 |
263 Call<PpapiPluginMsg_UDPSocket_JoinGroupReply>( | 237 Call<PpapiPluginMsg_UDPSocket_JoinGroupReply>( |
264 BROWSER, | 238 BROWSER, |
265 PpapiHostMsg_UDPSocket_JoinGroup(*group), | 239 PpapiHostMsg_UDPSocket_JoinGroup(*group), |
(...skipping 12 matching lines...) Expand all Loading... |
278 Call<PpapiPluginMsg_UDPSocket_LeaveGroupReply>( | 252 Call<PpapiPluginMsg_UDPSocket_LeaveGroupReply>( |
279 BROWSER, | 253 BROWSER, |
280 PpapiHostMsg_UDPSocket_LeaveGroup(*group), | 254 PpapiHostMsg_UDPSocket_LeaveGroup(*group), |
281 base::Bind(&UDPSocketResourceBase::OnPluginMsgGeneralReply, | 255 base::Bind(&UDPSocketResourceBase::OnPluginMsgGeneralReply, |
282 base::Unretained(this), | 256 base::Unretained(this), |
283 callback), | 257 callback), |
284 callback); | 258 callback); |
285 return PP_OK_COMPLETIONPENDING; | 259 return PP_OK_COMPLETIONPENDING; |
286 } | 260 } |
287 | 261 |
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( | 262 void UDPSocketResourceBase::OnPluginMsgGeneralReply( |
307 scoped_refptr<TrackedCallback> callback, | 263 scoped_refptr<TrackedCallback> callback, |
308 const ResourceMessageReplyParams& params) { | 264 const ResourceMessageReplyParams& params) { |
309 if (TrackedCallback::IsPending(callback)) | 265 if (TrackedCallback::IsPending(callback)) |
310 RunCallback(callback, params.result()); | 266 RunCallback(callback, params.result(), private_api_); |
311 } | 267 } |
312 | 268 |
313 void UDPSocketResourceBase::OnPluginMsgBindReply( | 269 void UDPSocketResourceBase::OnPluginMsgBindReply( |
314 const ResourceMessageReplyParams& params, | 270 const ResourceMessageReplyParams& params, |
315 const PP_NetAddress_Private& bound_addr) { | 271 const PP_NetAddress_Private& bound_addr) { |
316 // It is possible that |bind_callback_| is pending while |closed_| is true: | 272 // 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 | 273 // 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_| | 274 // abort |bind_callback_|. We don't want to update |bound_| or |bound_addr_| |
319 // in that case. | 275 // in that case. |
320 if (!TrackedCallback::IsPending(bind_callback_) || closed_) | 276 if (!TrackedCallback::IsPending(bind_callback_) || closed_) |
321 return; | 277 return; |
322 | 278 |
323 if (params.result() == PP_OK) | 279 if (params.result() == PP_OK) |
324 bound_ = true; | 280 bound_ = true; |
325 bound_addr_ = bound_addr; | 281 bound_addr_ = bound_addr; |
326 RunCallback(bind_callback_, params.result()); | 282 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 } | 283 } |
371 | 284 |
372 void UDPSocketResourceBase::OnPluginMsgSendToReply( | 285 void UDPSocketResourceBase::OnPluginMsgSendToReply( |
373 const ResourceMessageReplyParams& params, | 286 const ResourceMessageReplyParams& params, |
374 int32_t bytes_written) { | 287 int32_t bytes_written) { |
375 // This can be empty if the socket was closed, but there are still tasks | 288 // This can be empty if the socket was closed, but there are still tasks |
376 // to be posted for this resource. | 289 // to be posted for this resource. |
377 if (sendto_callbacks_.empty()) | 290 if (sendto_callbacks_.empty()) |
378 return; | 291 return; |
379 | 292 |
380 scoped_refptr<TrackedCallback> callback = sendto_callbacks_.front(); | 293 scoped_refptr<TrackedCallback> callback = sendto_callbacks_.front(); |
381 sendto_callbacks_.pop(); | 294 sendto_callbacks_.pop(); |
382 if (!TrackedCallback::IsPending(callback)) | 295 if (!TrackedCallback::IsPending(callback)) |
383 return; | 296 return; |
384 | 297 |
385 if (params.result() == PP_OK) | 298 if (params.result() == PP_OK) |
386 RunCallback(callback, bytes_written); | 299 RunCallback(callback, bytes_written, private_api_); |
387 else | 300 else |
388 RunCallback(callback, params.result()); | 301 RunCallback(callback, params.result(), private_api_); |
389 } | 302 } |
390 | 303 |
391 void UDPSocketResourceBase::RunCallback(scoped_refptr<TrackedCallback> callback, | 304 // static |
392 int32_t pp_result) { | 305 void UDPSocketResourceBase::SlotBecameAvailable(PP_Resource resource) { |
393 callback->Run(ConvertNetworkAPIErrorForCompatibility(pp_result, | 306 ProxyLock::AssertAcquired(); |
394 private_api_)); | 307 thunk::EnterResourceNoLock<thunk::PPB_UDPSocket_API> enter(resource, false); |
395 } | 308 if (enter.failed()) |
| 309 return; |
| 310 auto thiz(static_cast<UDPSocketResourceBase*>(enter.resource())); |
396 | 311 |
397 int32_t UDPSocketResourceBase::SetRecvFromOutput( | 312 if (!thiz->closed_) |
398 int32_t browser_result, | 313 thiz->Post(BROWSER, PpapiHostMsg_UDPSocket_RecvSlotAvailable()); |
399 const std::string& data, | |
400 const PP_NetAddress_Private& addr, | |
401 char* output_buffer, | |
402 int32_t num_bytes, | |
403 PP_Resource* output_addr) { | |
404 DCHECK_GE(num_bytes, static_cast<int32_t>(data.size())); | |
405 | |
406 int32_t result = browser_result; | |
407 if (result == PP_OK && output_addr) { | |
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 } | 314 } |
424 | 315 |
425 } // namespace proxy | 316 } // namespace proxy |
426 } // namespace ppapi | 317 } // namespace ppapi |
OLD | NEW |