1 // Copyright (c) 2012 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.
5 #include "net/websockets/websocket_throttle.h"
9 #include "base/hash_tables.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/singleton.h"
12 #include "base/message_loop.h"
13 #include "base/string_number_conversions.h"
14 #include "base/string_util.h"
15 #include "base/stringprintf.h"
16 #include "net/base/io_buffer.h"
17 #include "net/socket_stream/socket_stream.h"
18 #include "net/websockets/websocket_job.h"
22 static std::string
IPEndPointToHashkey(const IPEndPoint
& endpoint
) {
23 return base::StringPrintf("%d:%s",
25 base::HexEncode(&endpoint
.address()[0],
26 endpoint
.address().size()).c_str());
29 WebSocketThrottle::WebSocketThrottle() {
32 WebSocketThrottle::~WebSocketThrottle() {
33 DCHECK(queue_
.empty());
34 DCHECK(addr_map_
.empty());
38 WebSocketThrottle
* WebSocketThrottle::GetInstance() {
39 return Singleton
<WebSocketThrottle
>::get();
42 void WebSocketThrottle::PutInQueue(WebSocketJob
* job
) {
43 queue_
.push_back(job
);
44 const AddressList
& address_list
= job
->address_list();
45 base::hash_set
<std::string
> address_set
;
46 for (AddressList::const_iterator addr_iter
= address_list
.begin();
47 addr_iter
!= address_list
.end();
49 std::string addrkey
= IPEndPointToHashkey(*addr_iter
);
51 // If |addrkey| is already processed, don't do it again.
52 if (address_set
.find(addrkey
) != address_set
.end())
54 address_set
.insert(addrkey
);
56 ConnectingAddressMap::iterator iter
= addr_map_
.find(addrkey
);
57 if (iter
== addr_map_
.end()) {
58 ConnectingQueue
* queue
= new ConnectingQueue();
59 queue
->push_back(job
);
60 addr_map_
[addrkey
] = queue
;
62 iter
->second
->push_back(job
);
64 DVLOG(1) << "Waiting on " << addrkey
;
69 void WebSocketThrottle::RemoveFromQueue(WebSocketJob
* job
) {
70 bool in_queue
= false;
71 for (ConnectingQueue::iterator iter
= queue_
.begin();
82 const AddressList
& address_list
= job
->address_list();
83 base::hash_set
<std::string
> address_set
;
84 for (AddressList::const_iterator addr_iter
= address_list
.begin();
85 addr_iter
!= address_list
.end();
87 std::string addrkey
= IPEndPointToHashkey(*addr_iter
);
88 // If |addrkey| is already processed, don't do it again.
89 if (address_set
.find(addrkey
) != address_set
.end())
91 address_set
.insert(addrkey
);
93 ConnectingAddressMap::iterator iter
= addr_map_
.find(addrkey
);
94 DCHECK(iter
!= addr_map_
.end());
96 ConnectingQueue
* queue
= iter
->second
;
97 // Job may not be front of queue when job is closed early while waiting.
98 for (ConnectingQueue::iterator iter
= queue
->begin();
106 if (queue
->empty()) {
108 addr_map_
.erase(iter
);
113 void WebSocketThrottle::WakeupSocketIfNecessary() {
114 for (ConnectingQueue::iterator iter
= queue_
.begin();
115 iter
!= queue_
.end();
117 WebSocketJob
* job
= *iter
;
118 if (!job
->IsWaiting())
121 bool should_wakeup
= true;
122 const AddressList
& address_list
= job
->address_list();
123 for (AddressList::const_iterator addr_iter
= address_list
.begin();
124 addr_iter
!= address_list
.end();
126 std::string addrkey
= IPEndPointToHashkey(*addr_iter
);
127 ConnectingAddressMap::iterator iter
= addr_map_
.find(addrkey
);
128 DCHECK(iter
!= addr_map_
.end());
129 ConnectingQueue
* queue
= iter
->second
;
130 if (job
!= queue
->front()) {
131 should_wakeup
= false;