OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 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 "net/socket/websocket_transport_client_socket_pool.h" | |
6 | |
7 #include <algorithm> | |
8 #include <limits> | |
tyoshino (SeeGerritForStatus)
2014/06/20 12:12:07
remove
Adam Rice
2014/06/23 10:06:26
Done.
| |
9 #include <map> | |
tyoshino (SeeGerritForStatus)
2014/06/20 12:12:07
remove
Adam Rice
2014/06/23 10:06:26
Done.
| |
10 #include <utility> | |
tyoshino (SeeGerritForStatus)
2014/06/20 12:12:07
remove
Adam Rice
2014/06/23 10:06:26
Done.
| |
11 | |
12 #include "base/compiler_specific.h" | |
13 #include "base/logging.h" | |
14 #include "base/memory/singleton.h" | |
tyoshino (SeeGerritForStatus)
2014/06/20 12:12:07
remove
Adam Rice
2014/06/23 10:06:26
Done.
| |
15 #include "base/numerics/safe_conversions.h" | |
16 #include "base/stl_util.h" | |
tyoshino (SeeGerritForStatus)
2014/06/20 12:12:06
remove
Adam Rice
2014/06/23 10:06:26
Done.
| |
17 #include "base/strings/string_util.h" | |
18 #include "base/time/time.h" | |
19 #include "base/values.h" | |
20 #include "net/base/ip_endpoint.h" | |
tyoshino (SeeGerritForStatus)
2014/06/20 12:12:06
can be removed?
Adam Rice
2014/06/23 10:06:26
Done.
| |
21 #include "net/base/net_errors.h" | |
22 #include "net/base/net_log.h" | |
23 #include "net/socket/client_socket_handle.h" | |
24 #include "net/socket/client_socket_pool_base.h" | |
25 #include "net/socket/websocket_endpoint_lock_manager.h" | |
26 #include "net/socket/websocket_transport_connect_sub_job.h" | |
27 | |
28 namespace net { | |
29 | |
30 namespace { | |
31 | |
32 using base::TimeDelta; | |
33 | |
34 // TODO(ricea): For now, we implement a global timeout for compatability with | |
35 // TransportConnectJob. Since WebSocketTransportConnectJob controls the address | |
36 // selection process more tightly, it could do something smarter here. | |
37 const int kTransportConnectJobTimeoutInSeconds = 240; // 4 minutes. | |
38 | |
39 } // namespace | |
40 | |
41 WebSocketTransportConnectJob::WebSocketTransportConnectJob( | |
42 const std::string& group_name, | |
43 RequestPriority priority, | |
44 const scoped_refptr<TransportSocketParams>& params, | |
45 TimeDelta timeout_duration, | |
46 const CompletionCallback& callback, | |
47 ClientSocketFactory* client_socket_factory, | |
48 HostResolver* host_resolver, | |
49 ClientSocketHandle* handle, | |
50 Delegate* delegate, | |
51 NetLog* pool_net_log, | |
52 const BoundNetLog& request_net_log) | |
53 : ConnectJob(group_name, | |
54 timeout_duration, | |
55 priority, | |
56 delegate, | |
57 BoundNetLog::Make(pool_net_log, NetLog::SOURCE_CONNECT_JOB)), | |
58 helper_(params, client_socket_factory, host_resolver, &connect_timing_), | |
59 race_result_(TransportConnectJobHelper::CONNECTION_LATENCY_UNKNOWN), | |
60 handle_(handle), | |
61 callback_(callback), | |
62 request_net_log_(request_net_log), | |
63 had_ipv4_(false), | |
64 had_ipv6_(false) { | |
65 helper_.SetOnIOComplete(this); | |
66 } | |
67 | |
68 WebSocketTransportConnectJob::~WebSocketTransportConnectJob() {} | |
69 | |
70 LoadState WebSocketTransportConnectJob::GetLoadState() const { | |
71 LoadState load_state = LOAD_STATE_RESOLVING_HOST; | |
72 if (ipv6_job_) | |
73 load_state = ipv6_job_->GetLoadState(); | |
74 // This method should return LOAD_STATE_CONNECTING in preference to | |
75 // LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET when possible because "waiting for | |
76 // available socket" implies that nothing is happening. | |
77 if (ipv4_job_ && load_state != LOAD_STATE_CONNECTING) | |
78 load_state = ipv4_job_->GetLoadState(); | |
79 return load_state; | |
80 } | |
81 | |
82 int WebSocketTransportConnectJob::DoResolveHost() { | |
83 return helper_.DoResolveHost(priority(), net_log()); | |
84 } | |
85 | |
86 int WebSocketTransportConnectJob::DoResolveHostComplete(int result) { | |
87 return helper_.DoResolveHostComplete(result, net_log()); | |
88 } | |
89 | |
90 int WebSocketTransportConnectJob::DoTransportConnect() { | |
91 AddressList ipv4_addresses; | |
92 AddressList ipv6_addresses; | |
93 int result = ERR_UNEXPECTED; | |
94 helper_.set_next_state( | |
95 TransportConnectJobHelper::STATE_TRANSPORT_CONNECT_COMPLETE); | |
96 | |
97 for (AddressList::const_iterator it = helper_.addresses().begin(); | |
98 it != helper_.addresses().end(); | |
99 ++it) { | |
100 switch (it->GetFamily()) { | |
101 case ADDRESS_FAMILY_IPV4: | |
102 ipv4_addresses.push_back(*it); | |
103 break; | |
104 | |
105 case ADDRESS_FAMILY_IPV6: | |
106 ipv6_addresses.push_back(*it); | |
107 break; | |
108 | |
109 default: | |
110 DVLOG(1) << "Unexpected ADDRESS_FAMILY: " << it->GetFamily(); | |
111 break; | |
112 } | |
113 } | |
114 | |
115 if (!ipv4_addresses.empty()) { | |
116 had_ipv4_ = true; | |
117 ipv4_job_.reset(new WebSocketTransportConnectSubJob( | |
118 ipv4_addresses, this, SUB_JOB_IPV4)); | |
119 } | |
120 | |
121 if (!ipv6_addresses.empty()) { | |
122 had_ipv6_ = true; | |
123 ipv6_job_.reset(new WebSocketTransportConnectSubJob( | |
124 ipv6_addresses, this, SUB_JOB_IPV6)); | |
125 result = ipv6_job_->Start(); | |
126 switch (result) { | |
127 case OK: | |
128 SetSocket(ipv6_job_->PassSocket()); | |
129 race_result_ = | |
130 had_ipv4_ | |
131 ? TransportConnectJobHelper::CONNECTION_LATENCY_IPV6_RACEABLE | |
132 : TransportConnectJobHelper::CONNECTION_LATENCY_IPV6_SOLO; | |
133 return result; | |
134 | |
135 case ERR_IO_PENDING: | |
136 if (ipv4_job_) { | |
137 // This use of base::Unretained is safe because |fallback_timer_| is | |
138 // owned by this object. | |
139 fallback_timer_.Start( | |
140 FROM_HERE, | |
141 TimeDelta::FromMilliseconds( | |
142 TransportConnectJobHelper::kIPv6FallbackTimerInMs), | |
143 base::Bind(&WebSocketTransportConnectJob::StartIPv4JobAsync, | |
144 base::Unretained(this))); | |
145 } | |
146 return result; | |
147 | |
148 default: | |
149 ipv6_job_.reset(); | |
150 } | |
151 } | |
152 | |
153 DCHECK(!ipv6_job_); | |
154 if (ipv4_job_) { | |
155 result = ipv4_job_->Start(); | |
156 if (result == OK) { | |
157 SetSocket(ipv4_job_->PassSocket()); | |
158 race_result_ = | |
159 had_ipv6_ | |
160 ? TransportConnectJobHelper::CONNECTION_LATENCY_IPV4_WINS_RACE | |
161 : TransportConnectJobHelper::CONNECTION_LATENCY_IPV4_NO_RACE; | |
162 } | |
163 } | |
164 | |
165 return result; | |
166 } | |
167 | |
168 int WebSocketTransportConnectJob::DoTransportConnectComplete(int result) { | |
169 if (result == OK) | |
170 helper_.HistogramDuration(race_result_); | |
171 return result; | |
172 } | |
173 | |
174 void WebSocketTransportConnectJob::OnSubJobComplete( | |
175 int result, | |
176 WebSocketTransportConnectSubJob* job) { | |
177 if (result == OK) { | |
178 switch (job->type()) { | |
179 case SUB_JOB_IPV4: | |
180 race_result_ = | |
181 had_ipv6_ | |
182 ? TransportConnectJobHelper::CONNECTION_LATENCY_IPV4_WINS_RACE | |
183 : TransportConnectJobHelper::CONNECTION_LATENCY_IPV4_NO_RACE; | |
184 break; | |
185 | |
186 case SUB_JOB_IPV6: | |
187 race_result_ = | |
188 had_ipv4_ | |
189 ? TransportConnectJobHelper::CONNECTION_LATENCY_IPV6_RACEABLE | |
190 : TransportConnectJobHelper::CONNECTION_LATENCY_IPV6_SOLO; | |
191 break; | |
192 } | |
193 SetSocket(job->PassSocket()); | |
194 | |
195 // Make sure all connections are cancelled even if this object fails to be | |
196 // deleted. | |
197 ipv4_job_.reset(); | |
198 ipv6_job_.reset(); | |
199 } else { | |
200 switch (job->type()) { | |
201 case SUB_JOB_IPV4: | |
202 ipv4_job_.reset(); | |
203 break; | |
204 | |
205 case SUB_JOB_IPV6: | |
206 ipv6_job_.reset(); | |
207 if (ipv4_job_ && !ipv4_job_->started()) { | |
208 fallback_timer_.Stop(); | |
209 result = ipv4_job_->Start(); | |
210 if (result != ERR_IO_PENDING) { | |
211 OnSubJobComplete(result, ipv4_job_.get()); | |
212 return; | |
213 } | |
214 } | |
215 break; | |
216 } | |
217 if (ipv4_job_ || ipv6_job_) | |
218 return; | |
219 } | |
220 helper_.OnIOComplete(this, result); | |
221 } | |
222 | |
223 void WebSocketTransportConnectJob::StartIPv4JobAsync() { | |
224 DCHECK(ipv4_job_); | |
225 int result = ipv4_job_->Start(); | |
226 if (result != ERR_IO_PENDING) | |
227 OnSubJobComplete(result, ipv4_job_.get()); | |
228 } | |
229 | |
230 int WebSocketTransportConnectJob::ConnectInternal() { | |
231 return helper_.DoConnectInternal(this); | |
232 } | |
233 | |
234 WebSocketTransportClientSocketPool::WebSocketTransportClientSocketPool( | |
235 int max_sockets, | |
236 int max_sockets_per_group, | |
237 ClientSocketPoolHistograms* histograms, | |
238 HostResolver* host_resolver, | |
239 ClientSocketFactory* client_socket_factory, | |
240 NetLog* net_log) | |
241 : TransportClientSocketPool(max_sockets, | |
242 max_sockets_per_group, | |
243 histograms, | |
244 host_resolver, | |
245 client_socket_factory, | |
246 net_log), | |
247 connect_job_delegate_(this), | |
248 histograms_(histograms), | |
249 pool_net_log_(net_log), | |
250 client_socket_factory_(client_socket_factory), | |
251 host_resolver_(host_resolver), | |
252 max_sockets_(max_sockets), | |
253 handed_out_socket_count_(0), | |
254 weak_factory_(this) {} | |
255 | |
256 WebSocketTransportClientSocketPool::~WebSocketTransportClientSocketPool() { | |
Johnny
2014/06/20 21:32:58
I think I'm surprised by these dcheck's. What's th
Adam Rice
2014/06/23 10:06:26
I'm not completely sure about this, since unlike t
| |
257 DCHECK(pending_connects_.empty()); | |
258 DCHECK_EQ(0, handed_out_socket_count_); | |
259 DCHECK(stalled_request_queue_.empty()); | |
260 DCHECK(stalled_request_map_.empty()); | |
261 } | |
262 | |
263 // static | |
264 void WebSocketTransportClientSocketPool::UnlockEndpoint( | |
265 ClientSocketHandle* handle) { | |
266 DCHECK(handle->is_initialized()); | |
267 WebSocketEndpointLockManager::GetInstance()->UnlockSocket(handle->socket()); | |
268 } | |
269 | |
270 int WebSocketTransportClientSocketPool::RequestSocket( | |
271 const std::string& group_name, | |
272 const void* params, | |
273 RequestPriority priority, | |
274 ClientSocketHandle* handle, | |
275 const CompletionCallback& callback, | |
276 const BoundNetLog& request_net_log) { | |
277 DCHECK(params); | |
278 const scoped_refptr<TransportSocketParams>& casted_params = | |
279 *static_cast<const scoped_refptr<TransportSocketParams>*>(params); | |
280 | |
281 NetLogTcpClientSocketPoolRequestedSocket(request_net_log, &casted_params); | |
282 | |
283 CHECK(!callback.is_null()); | |
284 CHECK(handle); | |
285 | |
286 request_net_log.BeginEvent(NetLog::TYPE_SOCKET_POOL); | |
287 | |
288 if (ReachedMaxSocketsLimit() && !casted_params->ignore_limits()) { | |
289 request_net_log.AddEvent(NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS); | |
290 // TODO(ricea): Use emplace_back when C++11 becomes allowed. | |
291 StalledRequest request( | |
292 casted_params, priority, handle, callback, request_net_log); | |
293 stalled_request_queue_.push_back(request); | |
294 StalledRequestQueue::iterator iterator = stalled_request_queue_.end(); | |
295 --iterator; | |
296 DCHECK_EQ(handle, iterator->handle); | |
297 stalled_request_map_.insert( | |
298 StalledRequestMap::value_type(handle, iterator)); | |
tyoshino (SeeGerritForStatus)
2014/06/20 12:12:07
please write why we can use the std::list iterator
Adam Rice
2014/06/23 10:06:26
Done.
| |
299 return ERR_IO_PENDING; | |
300 } | |
301 | |
302 scoped_ptr<WebSocketTransportConnectJob> connect_job( | |
303 new WebSocketTransportConnectJob(group_name, | |
304 priority, | |
305 casted_params, | |
306 ConnectionTimeout(), | |
307 callback, | |
308 client_socket_factory_, | |
309 host_resolver_, | |
310 handle, | |
311 &connect_job_delegate_, | |
312 pool_net_log_, | |
313 request_net_log)); | |
314 | |
315 int rv = connect_job->Connect(); | |
316 // Regardless of the outcome of |connect_job|, it will always be bound to | |
317 // |handle|, since this pool uses early-binding. So the binding is logged | |
318 // here, without waiting for the result. | |
319 request_net_log.AddEvent( | |
320 NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB, | |
321 connect_job->net_log().source().ToEventParametersCallback()); | |
322 if (rv == OK) { | |
323 HandOutSocket(connect_job->PassSocket(), | |
324 connect_job->connect_timing(), | |
325 handle, | |
326 request_net_log); | |
327 request_net_log.EndEvent(NetLog::TYPE_SOCKET_POOL); | |
328 } else if (rv == ERR_IO_PENDING) { | |
329 // TODO(ricea): Implement backup job timer? | |
330 AddJob(handle, connect_job.Pass()); | |
331 } else { | |
332 scoped_ptr<StreamSocket> error_socket; | |
333 connect_job->GetAdditionalErrorState(handle); | |
334 error_socket = connect_job->PassSocket(); | |
335 if (error_socket) { | |
336 HandOutSocket(error_socket.Pass(), | |
337 connect_job->connect_timing(), | |
338 handle, | |
339 request_net_log); | |
340 } | |
341 } | |
342 | |
343 if (rv != ERR_IO_PENDING) { | |
344 request_net_log.EndEventWithNetErrorCode(NetLog::TYPE_SOCKET_POOL, rv); | |
345 } | |
346 | |
347 return rv; | |
348 } | |
349 | |
350 void WebSocketTransportClientSocketPool::RequestSockets( | |
351 const std::string& group_name, | |
352 const void* params, | |
353 int num_sockets, | |
354 const BoundNetLog& net_log) { | |
355 NOTIMPLEMENTED(); | |
356 } | |
357 | |
358 void WebSocketTransportClientSocketPool::CancelRequest( | |
359 const std::string& group_name, | |
360 ClientSocketHandle* handle) { | |
361 if (DeleteStalledRequest(handle)) | |
362 return; | |
363 if (!DeleteJob(handle)) | |
364 pending_callbacks_.erase(handle); | |
365 if (!ReachedMaxSocketsLimit() && !stalled_request_queue_.empty()) | |
366 ActivateStalledRequest(); | |
367 } | |
368 | |
369 void WebSocketTransportClientSocketPool::ReleaseSocket( | |
370 const std::string& group_name, | |
371 scoped_ptr<StreamSocket> socket, | |
372 int id) { | |
373 WebSocketEndpointLockManager::GetInstance()->UnlockSocket(socket.get()); | |
374 CHECK_GT(handed_out_socket_count_, 0); | |
375 --handed_out_socket_count_; | |
376 if (!ReachedMaxSocketsLimit() && !stalled_request_queue_.empty()) | |
377 ActivateStalledRequest(); | |
378 } | |
379 | |
380 void WebSocketTransportClientSocketPool::FlushWithError(int error) { | |
Johnny
2014/06/20 21:32:58
Are there re-entrance concerns with these loops? E
Adam Rice
2014/06/23 10:06:26
Well spotted! I have added tests and a flag to gua
| |
381 for (PendingConnectsMap::iterator it = pending_connects_.begin(); | |
382 it != pending_connects_.end(); | |
383 ++it) { | |
384 InvokeUserCallbackLater( | |
385 it->second->handle(), it->second->callback(), error); | |
386 delete it->second; | |
387 } | |
388 pending_connects_.clear(); | |
389 for (StalledRequestQueue::iterator it = stalled_request_queue_.begin(); | |
390 it != stalled_request_queue_.end(); | |
391 ++it) { | |
392 InvokeUserCallbackLater(it->handle, it->callback, error); | |
393 } | |
394 stalled_request_map_.clear(); | |
395 stalled_request_queue_.clear(); | |
396 handed_out_socket_count_ = 0; | |
397 } | |
398 | |
399 void WebSocketTransportClientSocketPool::CloseIdleSockets() { | |
400 // We have no idle sockets. | |
401 } | |
402 | |
403 int WebSocketTransportClientSocketPool::IdleSocketCount() const { | |
404 return 0; | |
405 } | |
406 | |
407 int WebSocketTransportClientSocketPool::IdleSocketCountInGroup( | |
408 const std::string& group_name) const { | |
409 return 0; | |
410 } | |
411 | |
412 LoadState WebSocketTransportClientSocketPool::GetLoadState( | |
413 const std::string& group_name, | |
414 const ClientSocketHandle* handle) const { | |
415 if (stalled_request_map_.find(handle) != stalled_request_map_.end()) | |
416 return LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET; | |
417 if (pending_callbacks_.count(handle)) | |
418 return LOAD_STATE_CONNECTING; | |
419 return LookupConnectJob(handle)->GetLoadState(); | |
420 } | |
421 | |
422 base::DictionaryValue* WebSocketTransportClientSocketPool::GetInfoAsValue( | |
423 const std::string& name, | |
424 const std::string& type, | |
425 bool include_nested_pools) const { | |
426 base::DictionaryValue* dict = new base::DictionaryValue(); | |
427 dict->SetString("name", name); | |
428 dict->SetString("type", type); | |
429 dict->SetInteger("handed_out_socket_count", handed_out_socket_count_); | |
430 dict->SetInteger("connecting_socket_count", pending_connects_.size()); | |
431 dict->SetInteger("idle_socket_count", 0); | |
432 dict->SetInteger("max_socket_count", max_sockets_); | |
433 dict->SetInteger("max_sockets_per_group", max_sockets_); | |
434 dict->SetInteger("pool_generation_number", 0); | |
435 return dict; | |
436 } | |
437 | |
438 TimeDelta WebSocketTransportClientSocketPool::ConnectionTimeout() const { | |
439 return TimeDelta::FromSeconds(kTransportConnectJobTimeoutInSeconds); | |
440 } | |
441 | |
442 ClientSocketPoolHistograms* WebSocketTransportClientSocketPool::histograms() | |
443 const { | |
444 return histograms_; | |
445 } | |
446 | |
447 bool WebSocketTransportClientSocketPool::IsStalled() const { | |
448 return !stalled_request_queue_.empty(); | |
449 } | |
450 | |
451 void WebSocketTransportClientSocketPool::OnConnectJobComplete( | |
452 int result, | |
453 WebSocketTransportConnectJob* job) { | |
454 DCHECK_NE(ERR_IO_PENDING, result); | |
455 | |
456 scoped_ptr<StreamSocket> socket = job->PassSocket(); | |
457 | |
458 BoundNetLog request_net_log = job->request_net_log(); | |
459 CompletionCallback callback = job->callback(); | |
460 LoadTimingInfo::ConnectTiming connect_timing = job->connect_timing(); | |
461 | |
462 ClientSocketHandle* const handle = job->handle(); | |
463 bool handed_out_socket = false; | |
464 | |
465 if (result == OK) { | |
466 DCHECK(socket.get()); | |
467 handed_out_socket = true; | |
468 HandOutSocket(socket.Pass(), connect_timing, handle, request_net_log); | |
469 request_net_log.EndEvent(NetLog::TYPE_SOCKET_POOL); | |
470 } else { | |
471 // If we got a socket, it must contain error information so pass that | |
472 // up so that the caller can retrieve it. | |
473 job->GetAdditionalErrorState(handle); | |
474 if (socket.get()) { | |
475 handed_out_socket = true; | |
476 HandOutSocket(socket.Pass(), connect_timing, handle, request_net_log); | |
477 } | |
478 request_net_log.EndEventWithNetErrorCode(NetLog::TYPE_SOCKET_POOL, result); | |
479 } | |
480 bool delete_succeeded = DeleteJob(handle); | |
481 DCHECK(delete_succeeded); | |
482 if (!handed_out_socket && !stalled_request_queue_.empty() && | |
483 !ReachedMaxSocketsLimit()) | |
484 ActivateStalledRequest(); | |
485 InvokeUserCallbackLater(handle, callback, result); | |
486 } | |
487 | |
488 void WebSocketTransportClientSocketPool::InvokeUserCallbackLater( | |
489 ClientSocketHandle* handle, | |
490 const CompletionCallback& callback, | |
491 int rv) { | |
492 DCHECK(!pending_callbacks_.count(handle)); | |
493 pending_callbacks_.insert(handle); | |
494 base::MessageLoop::current()->PostTask( | |
495 FROM_HERE, | |
496 base::Bind(&WebSocketTransportClientSocketPool::InvokeUserCallback, | |
497 weak_factory_.GetWeakPtr(), | |
498 handle, | |
499 callback, | |
500 rv)); | |
501 } | |
502 | |
503 void WebSocketTransportClientSocketPool::InvokeUserCallback( | |
504 ClientSocketHandle* handle, | |
505 const CompletionCallback& callback, | |
506 int rv) { | |
507 if (pending_callbacks_.erase(handle)) | |
508 callback.Run(rv); | |
509 } | |
510 | |
511 bool WebSocketTransportClientSocketPool::ReachedMaxSocketsLimit() const { | |
512 return handed_out_socket_count_ >= max_sockets_ || | |
513 base::checked_cast<int>(pending_connects_.size()) >= | |
514 max_sockets_ - handed_out_socket_count_; | |
515 } | |
516 | |
517 void WebSocketTransportClientSocketPool::HandOutSocket( | |
518 scoped_ptr<StreamSocket> socket, | |
519 const LoadTimingInfo::ConnectTiming& connect_timing, | |
520 ClientSocketHandle* handle, | |
521 const BoundNetLog& net_log) { | |
522 DCHECK(socket); | |
523 handle->SetSocket(socket.Pass()); | |
524 DCHECK_EQ(ClientSocketHandle::UNUSED, handle->reuse_type()); | |
525 DCHECK_EQ(0, handle->idle_time().InMicroseconds()); | |
526 handle->set_pool_id(0); | |
527 handle->set_connect_timing(connect_timing); | |
528 | |
529 net_log.AddEvent( | |
530 NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET, | |
531 handle->socket()->NetLog().source().ToEventParametersCallback()); | |
532 | |
533 ++handed_out_socket_count_; | |
534 } | |
535 | |
536 void WebSocketTransportClientSocketPool::AddJob( | |
537 ClientSocketHandle* handle, | |
538 scoped_ptr<WebSocketTransportConnectJob> connect_job) { | |
539 bool inserted = | |
540 pending_connects_.insert(PendingConnectsMap::value_type( | |
541 handle, connect_job.release())).second; | |
542 DCHECK(inserted); | |
543 } | |
544 | |
545 bool WebSocketTransportClientSocketPool::DeleteJob(ClientSocketHandle* handle) { | |
546 PendingConnectsMap::iterator it = pending_connects_.find(handle); | |
547 if (it == pending_connects_.end()) | |
548 return false; | |
549 delete it->second, it->second = NULL; | |
Johnny
2014/06/20 21:32:58
Could |it| be invalidated here?
Adam Rice
2014/06/23 10:06:26
No. I have added a comment and a DCHECK to clarify
| |
550 pending_connects_.erase(it); | |
551 return true; | |
552 } | |
553 | |
554 const WebSocketTransportConnectJob* | |
555 WebSocketTransportClientSocketPool::LookupConnectJob( | |
556 const ClientSocketHandle* handle) const { | |
557 PendingConnectsMap::const_iterator it = pending_connects_.find(handle); | |
558 CHECK(it != pending_connects_.end()); | |
559 return it->second; | |
560 } | |
561 | |
562 void WebSocketTransportClientSocketPool::ActivateStalledRequest() { | |
563 DCHECK(!stalled_request_queue_.empty()); | |
564 DCHECK(!ReachedMaxSocketsLimit()); | |
565 // Usually we will only be able to activate one stalled request at a time, | |
566 // however if all the connects fail synchronously for some reason, we may be | |
567 // able to clear the whole queue at once. | |
568 while (!stalled_request_queue_.empty() && !ReachedMaxSocketsLimit()) { | |
569 StalledRequest request(stalled_request_queue_.front()); | |
570 stalled_request_queue_.pop_front(); | |
571 stalled_request_map_.erase(request.handle); | |
572 int rv = RequestSocket("ignored", | |
573 &request.params, | |
574 request.priority, | |
575 request.handle, | |
576 request.callback, | |
577 request.net_log); | |
578 if (rv != ERR_IO_PENDING) | |
579 InvokeUserCallbackLater(request.handle, request.callback, rv); | |
580 } | |
581 } | |
582 | |
583 bool WebSocketTransportClientSocketPool::DeleteStalledRequest( | |
584 ClientSocketHandle* handle) { | |
585 StalledRequestMap::iterator it = stalled_request_map_.find(handle); | |
586 if (it == stalled_request_map_.end()) | |
587 return false; | |
588 stalled_request_queue_.erase(it->second); | |
589 stalled_request_map_.erase(it); | |
590 return true; | |
591 } | |
592 | |
593 WebSocketTransportClientSocketPool::ConnectJobDelegate::ConnectJobDelegate( | |
594 WebSocketTransportClientSocketPool* owner) | |
595 : owner_(owner) {} | |
596 | |
597 WebSocketTransportClientSocketPool::ConnectJobDelegate::~ConnectJobDelegate() {} | |
598 | |
599 void | |
600 WebSocketTransportClientSocketPool::ConnectJobDelegate::OnConnectJobComplete( | |
601 int result, | |
602 ConnectJob* job) { | |
603 owner_->OnConnectJobComplete(result, | |
604 static_cast<WebSocketTransportConnectJob*>(job)); | |
605 } | |
606 | |
607 WebSocketTransportClientSocketPool::StalledRequest::StalledRequest( | |
608 const scoped_refptr<TransportSocketParams>& params, | |
609 RequestPriority priority, | |
610 ClientSocketHandle* handle, | |
611 const CompletionCallback& callback, | |
612 const BoundNetLog& net_log) | |
613 : params(params), | |
614 priority(priority), | |
615 handle(handle), | |
616 callback(callback), | |
617 net_log(net_log) {} | |
618 | |
619 WebSocketTransportClientSocketPool::StalledRequest::~StalledRequest() {} | |
620 | |
621 } // namespace net | |
OLD | NEW |