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, this)); |
raymes
2015/03/09 07:43:01
Is this meant to be SlotBecameAvailableOnIOThread?
dmichael (off chromium)
2015/03/23 20:50:06
Good catch, thanks.
| |
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 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
136 PP_Bool UDPSocketResourceBase::GetBoundAddressImpl( | 137 PP_Bool UDPSocketResourceBase::GetBoundAddressImpl( |
137 PP_NetAddress_Private* addr) { | 138 PP_NetAddress_Private* addr) { |
138 if (!addr || !bound_ || closed_) | 139 if (!addr || !bound_ || closed_) |
139 return PP_FALSE; | 140 return PP_FALSE; |
140 | 141 |
141 *addr = bound_addr_; | 142 *addr = bound_addr_; |
142 return PP_TRUE; | 143 return PP_TRUE; |
143 } | 144 } |
144 | 145 |
145 int32_t UDPSocketResourceBase::RecvFromImpl( | 146 int32_t UDPSocketResourceBase::RecvFromImpl( |
146 char* buffer, | 147 char* buffer_out, |
147 int32_t num_bytes, | 148 int32_t num_bytes, |
148 PP_Resource* addr, | 149 PP_Resource* addr, |
149 scoped_refptr<TrackedCallback> callback) { | 150 scoped_refptr<TrackedCallback> callback) { |
150 if (!buffer || num_bytes <= 0) | 151 return recv_filter_->RequestData(pp_resource(), num_bytes, buffer_out, addr, |
151 return PP_ERROR_BADARGUMENT; | 152 callback); |
152 if (!bound_) | |
153 return PP_ERROR_FAILED; | |
154 if (TrackedCallback::IsPending(recvfrom_callback_)) | |
155 return PP_ERROR_INPROGRESS; | |
156 | |
157 if (recv_buffers_.empty()) { | |
158 read_buffer_ = buffer; | |
159 bytes_to_read_ = std::min(num_bytes, kMaxReadSize); | |
160 recvfrom_addr_resource_ = addr; | |
161 recvfrom_callback_ = callback; | |
162 | |
163 return PP_OK_COMPLETIONPENDING; | |
164 } else { | |
165 RecvBuffer& front = recv_buffers_.front(); | |
166 | |
167 if (num_bytes < static_cast<int32_t>(front.data.size())) | |
168 return PP_ERROR_MESSAGE_TOO_BIG; | |
169 | |
170 int32_t result = SetRecvFromOutput(front.result, front.data, front.addr, | |
171 buffer, num_bytes, addr); | |
172 | |
173 recv_buffers_.pop(); | |
174 Post(BROWSER, PpapiHostMsg_UDPSocket_RecvSlotAvailable()); | |
175 | |
176 return result; | |
177 } | |
178 } | 153 } |
179 | 154 |
180 PP_Bool UDPSocketResourceBase::GetRecvFromAddressImpl( | 155 PP_Bool UDPSocketResourceBase::GetRecvFromAddressImpl( |
181 PP_NetAddress_Private* addr) { | 156 PP_NetAddress_Private* addr) { |
182 if (!addr) | 157 if (!addr) |
183 return PP_FALSE; | 158 return PP_FALSE; |
184 *addr = recvfrom_addr_; | 159 *addr = recv_filter_->GetLastAddrPrivate(pp_resource()); |
185 return PP_TRUE; | 160 return PP_TRUE; |
186 } | 161 } |
187 | 162 |
188 int32_t UDPSocketResourceBase::SendToImpl( | 163 int32_t UDPSocketResourceBase::SendToImpl( |
189 const char* buffer, | 164 const char* buffer, |
190 int32_t num_bytes, | 165 int32_t num_bytes, |
191 const PP_NetAddress_Private* addr, | 166 const PP_NetAddress_Private* addr, |
192 scoped_refptr<TrackedCallback> callback) { | 167 scoped_refptr<TrackedCallback> callback) { |
193 if (!buffer || num_bytes <= 0 || !addr) | 168 if (!buffer || num_bytes <= 0 || !addr) |
194 return PP_ERROR_BADARGUMENT; | 169 return PP_ERROR_BADARGUMENT; |
(...skipping 19 matching lines...) Expand all Loading... | |
214 | 189 |
215 void UDPSocketResourceBase::CloseImpl() { | 190 void UDPSocketResourceBase::CloseImpl() { |
216 if(closed_) | 191 if(closed_) |
217 return; | 192 return; |
218 | 193 |
219 bound_ = false; | 194 bound_ = false; |
220 closed_ = true; | 195 closed_ = true; |
221 | 196 |
222 Post(BROWSER, PpapiHostMsg_UDPSocket_Close()); | 197 Post(BROWSER, PpapiHostMsg_UDPSocket_Close()); |
223 | 198 |
224 PostAbortIfNecessary(&bind_callback_); | 199 PostAbortIfNecessary(bind_callback_); |
225 PostAbortIfNecessary(&recvfrom_callback_); | |
226 while (!sendto_callbacks_.empty()) { | 200 while (!sendto_callbacks_.empty()) { |
227 scoped_refptr<TrackedCallback> callback = sendto_callbacks_.front(); | 201 scoped_refptr<TrackedCallback> callback = sendto_callbacks_.front(); |
228 sendto_callbacks_.pop(); | 202 sendto_callbacks_.pop(); |
229 PostAbortIfNecessary(&callback); | 203 PostAbortIfNecessary(callback); |
230 } | 204 } |
231 | 205 recv_filter_->RemoveUDPResource(pp_resource()); |
232 read_buffer_ = NULL; | |
233 bytes_to_read_ = -1; | |
234 } | |
235 | |
236 void UDPSocketResourceBase::OnReplyReceived( | |
237 const ResourceMessageReplyParams& params, | |
238 const IPC::Message& msg) { | |
239 PPAPI_BEGIN_MESSAGE_MAP(UDPSocketResourceBase, msg) | |
240 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( | |
241 PpapiPluginMsg_UDPSocket_PushRecvResult, | |
242 OnPluginMsgPushRecvResult) | |
243 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED( | |
244 PluginResource::OnReplyReceived(params, msg)) | |
245 PPAPI_END_MESSAGE_MAP() | |
246 } | |
247 | |
248 void UDPSocketResourceBase::PostAbortIfNecessary( | |
249 scoped_refptr<TrackedCallback>* callback) { | |
250 if (TrackedCallback::IsPending(*callback)) | |
251 (*callback)->PostAbort(); | |
252 } | 206 } |
253 | 207 |
254 void UDPSocketResourceBase::OnPluginMsgSetOptionReply( | 208 void UDPSocketResourceBase::OnPluginMsgSetOptionReply( |
255 scoped_refptr<TrackedCallback> callback, | 209 scoped_refptr<TrackedCallback> callback, |
256 const ResourceMessageReplyParams& params) { | 210 const ResourceMessageReplyParams& params) { |
257 if (TrackedCallback::IsPending(callback)) | 211 if (TrackedCallback::IsPending(callback)) |
258 RunCallback(callback, params.result()); | 212 RunCallback(callback, params.result(), private_api_); |
259 } | 213 } |
260 | 214 |
261 void UDPSocketResourceBase::OnPluginMsgBindReply( | 215 void UDPSocketResourceBase::OnPluginMsgBindReply( |
262 const ResourceMessageReplyParams& params, | 216 const ResourceMessageReplyParams& params, |
263 const PP_NetAddress_Private& bound_addr) { | 217 const PP_NetAddress_Private& bound_addr) { |
264 // It is possible that |bind_callback_| is pending while |closed_| is true: | 218 // It is possible that |bind_callback_| is pending while |closed_| is true: |
265 // CloseImpl() has been called, but a BindReply came earlier than the task to | 219 // CloseImpl() has been called, but a BindReply came earlier than the task to |
266 // abort |bind_callback_|. We don't want to update |bound_| or |bound_addr_| | 220 // abort |bind_callback_|. We don't want to update |bound_| or |bound_addr_| |
267 // in that case. | 221 // in that case. |
268 if (!TrackedCallback::IsPending(bind_callback_) || closed_) | 222 if (!TrackedCallback::IsPending(bind_callback_) || closed_) |
269 return; | 223 return; |
270 | 224 |
271 if (params.result() == PP_OK) | 225 if (params.result() == PP_OK) |
272 bound_ = true; | 226 bound_ = true; |
273 bound_addr_ = bound_addr; | 227 bound_addr_ = bound_addr; |
274 RunCallback(bind_callback_, params.result()); | 228 RunCallback(bind_callback_, params.result(), private_api_); |
275 } | |
276 | |
277 void UDPSocketResourceBase::OnPluginMsgPushRecvResult( | |
278 const ResourceMessageReplyParams& params, | |
279 int32_t result, | |
280 const std::string& data, | |
281 const PP_NetAddress_Private& addr) { | |
282 // TODO(yzshen): Support passing in a non-const string ref, so that we can | |
283 // eliminate one copy when storing the data in the buffer. | |
284 | |
285 DCHECK_LT(recv_buffers_.size(), kPluginReceiveBufferSlots); | |
286 | |
287 if (!TrackedCallback::IsPending(recvfrom_callback_) || !read_buffer_) { | |
288 recv_buffers_.push(RecvBuffer()); | |
289 RecvBuffer& back = recv_buffers_.back(); | |
290 back.result = result; | |
291 back.data = data; | |
292 back.addr = addr; | |
293 | |
294 return; | |
295 } | |
296 | |
297 DCHECK_EQ(recv_buffers_.size(), 0u); | |
298 | |
299 if (bytes_to_read_ < static_cast<int32_t>(data.size())) { | |
300 recv_buffers_.push(RecvBuffer()); | |
301 RecvBuffer& back = recv_buffers_.back(); | |
302 back.result = result; | |
303 back.data = data; | |
304 back.addr = addr; | |
305 | |
306 result = PP_ERROR_MESSAGE_TOO_BIG; | |
307 } else { | |
308 result = SetRecvFromOutput(result, data, addr, read_buffer_, bytes_to_read_, | |
309 recvfrom_addr_resource_); | |
310 Post(BROWSER, PpapiHostMsg_UDPSocket_RecvSlotAvailable()); | |
311 } | |
312 | |
313 read_buffer_ = NULL; | |
314 bytes_to_read_ = -1; | |
315 recvfrom_addr_resource_ = NULL; | |
316 | |
317 RunCallback(recvfrom_callback_, result); | |
318 } | 229 } |
319 | 230 |
320 void UDPSocketResourceBase::OnPluginMsgSendToReply( | 231 void UDPSocketResourceBase::OnPluginMsgSendToReply( |
321 const ResourceMessageReplyParams& params, | 232 const ResourceMessageReplyParams& params, |
322 int32_t bytes_written) { | 233 int32_t bytes_written) { |
323 // This can be empty if the socket was closed, but there are still tasks | 234 // This can be empty if the socket was closed, but there are still tasks |
324 // to be posted for this resource. | 235 // to be posted for this resource. |
325 if (sendto_callbacks_.empty()) | 236 if (sendto_callbacks_.empty()) |
326 return; | 237 return; |
327 | 238 |
328 scoped_refptr<TrackedCallback> callback = sendto_callbacks_.front(); | 239 scoped_refptr<TrackedCallback> callback = sendto_callbacks_.front(); |
329 sendto_callbacks_.pop(); | 240 sendto_callbacks_.pop(); |
330 if (!TrackedCallback::IsPending(callback)) | 241 if (!TrackedCallback::IsPending(callback)) |
331 return; | 242 return; |
332 | 243 |
333 if (params.result() == PP_OK) | 244 if (params.result() == PP_OK) |
334 RunCallback(callback, bytes_written); | 245 RunCallback(callback, bytes_written, private_api_); |
335 else | 246 else |
336 RunCallback(callback, params.result()); | 247 RunCallback(callback, params.result(), private_api_); |
337 } | 248 } |
338 | 249 |
339 void UDPSocketResourceBase::RunCallback(scoped_refptr<TrackedCallback> callback, | 250 void UDPSocketResourceBase::SlotBecameAvailableOnIOThread() { |
raymes
2015/03/10 02:53:15
Is it possible to add an assertion that we're on t
dmichael (off chromium)
2015/03/23 20:50:06
Done.
| |
340 int32_t pp_result) { | 251 // TODO(dmichael): This is kind of stupid; we ought to be able to build up |
341 callback->Run(ConvertNetworkAPIErrorForCompatibility(pp_result, | 252 // the right message and send it directly from the IO thread. Unfortunately, |
342 private_api_)); | 253 // we need to get a sequence number, which right now requires the ProxyLock. |
254 if (PpapiGlobals::Get() && PpapiGlobals::Get()->GetMainThreadMessageLoop()) { | |
255 PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(FROM_HERE, | |
256 RunWhileLocked(base::Bind(&UDPSocketResourceBase::SlotBecameAvailable, | |
257 this))); | |
258 } | |
343 } | 259 } |
344 | 260 |
345 int32_t UDPSocketResourceBase::SetRecvFromOutput( | 261 void UDPSocketResourceBase::SlotBecameAvailable() { |
346 int32_t browser_result, | 262 if (!closed_) |
347 const std::string& data, | 263 Post(BROWSER, PpapiHostMsg_UDPSocket_RecvSlotAvailable()); |
348 const PP_NetAddress_Private& addr, | |
349 char* output_buffer, | |
350 int32_t num_bytes, | |
351 PP_Resource* output_addr) { | |
352 DCHECK_GE(num_bytes, static_cast<int32_t>(data.size())); | |
353 | |
354 int32_t result = browser_result; | |
355 if (result == PP_OK && output_addr) { | |
356 thunk::EnterResourceCreationNoLock enter(pp_instance()); | |
357 if (enter.succeeded()) { | |
358 *output_addr = enter.functions()->CreateNetAddressFromNetAddressPrivate( | |
359 pp_instance(), addr); | |
360 } else { | |
361 result = PP_ERROR_FAILED; | |
362 } | |
363 } | |
364 | |
365 if (result == PP_OK && !data.empty()) | |
366 memcpy(output_buffer, data.c_str(), data.size()); | |
367 | |
368 recvfrom_addr_ = addr; | |
369 | |
370 return result == PP_OK ? static_cast<int32_t>(data.size()) : result; | |
371 } | 264 } |
372 | 265 |
373 } // namespace proxy | 266 } // namespace proxy |
374 } // namespace ppapi | 267 } // namespace ppapi |
OLD | NEW |