| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "net/websockets/websocket_throttle.h" | 5 #include "net/websockets/websocket_throttle.h" |
| 6 | 6 |
| 7 #include <algorithm> |
| 8 #include <set> |
| 7 #include <string> | 9 #include <string> |
| 8 | 10 |
| 9 #include "base/hash_tables.h" | |
| 10 #include "base/memory/ref_counted.h" | |
| 11 #include "base/memory/singleton.h" | 11 #include "base/memory/singleton.h" |
| 12 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
| 13 #include "base/string_number_conversions.h" | 13 #include "base/string_number_conversions.h" |
| 14 #include "base/string_util.h" | 14 #include "base/string_util.h" |
| 15 #include "base/stringprintf.h" | 15 #include "base/stringprintf.h" |
| 16 #include "net/base/io_buffer.h" | 16 #include "net/base/io_buffer.h" |
| 17 #include "net/socket_stream/socket_stream.h" | 17 #include "net/socket_stream/socket_stream.h" |
| 18 #include "net/websockets/websocket_job.h" | 18 #include "net/websockets/websocket_job.h" |
| 19 | 19 |
| 20 namespace net { | 20 namespace net { |
| 21 | 21 |
| 22 static std::string IPEndPointToHashkey(const IPEndPoint& endpoint) { | |
| 23 return base::StringPrintf("%d:%s", | |
| 24 endpoint.GetFamily(), | |
| 25 base::HexEncode(&endpoint.address()[0], | |
| 26 endpoint.address().size()).c_str()); | |
| 27 } | |
| 28 | |
| 29 WebSocketThrottle::WebSocketThrottle() { | 22 WebSocketThrottle::WebSocketThrottle() { |
| 30 } | 23 } |
| 31 | 24 |
| 32 WebSocketThrottle::~WebSocketThrottle() { | 25 WebSocketThrottle::~WebSocketThrottle() { |
| 33 DCHECK(queue_.empty()); | 26 DCHECK(queue_.empty()); |
| 34 DCHECK(addr_map_.empty()); | 27 DCHECK(addr_map_.empty()); |
| 35 } | 28 } |
| 36 | 29 |
| 37 // static | 30 // static |
| 38 WebSocketThrottle* WebSocketThrottle::GetInstance() { | 31 WebSocketThrottle* WebSocketThrottle::GetInstance() { |
| 39 return Singleton<WebSocketThrottle>::get(); | 32 return Singleton<WebSocketThrottle>::get(); |
| 40 } | 33 } |
| 41 | 34 |
| 42 void WebSocketThrottle::PutInQueue(WebSocketJob* job) { | 35 void WebSocketThrottle::PutInQueue(WebSocketJob* job) { |
| 43 queue_.push_back(job); | 36 queue_.push_back(job); |
| 44 const AddressList& address_list = job->address_list(); | 37 const AddressList& address_list = job->address_list(); |
| 45 base::hash_set<std::string> address_set; | 38 std::set<IPEndPoint> address_set; |
| 46 for (AddressList::const_iterator addr_iter = address_list.begin(); | 39 for (AddressList::const_iterator addr_iter = address_list.begin(); |
| 47 addr_iter != address_list.end(); | 40 addr_iter != address_list.end(); |
| 48 ++addr_iter) { | 41 ++addr_iter) { |
| 49 std::string addrkey = IPEndPointToHashkey(*addr_iter); | 42 const IPEndPoint& address = *addr_iter; |
| 43 // If |address| is already processed, don't do it again. |
| 44 if (!address_set.insert(address).second) |
| 45 continue; |
| 50 | 46 |
| 51 // If |addrkey| is already processed, don't do it again. | 47 ConnectingAddressMap::iterator iter = addr_map_.find(address); |
| 52 if (address_set.find(addrkey) != address_set.end()) | |
| 53 continue; | |
| 54 address_set.insert(addrkey); | |
| 55 | |
| 56 ConnectingAddressMap::iterator iter = addr_map_.find(addrkey); | |
| 57 if (iter == addr_map_.end()) { | 48 if (iter == addr_map_.end()) { |
| 58 ConnectingQueue* queue = new ConnectingQueue(); | 49 ConnectingQueue* queue = new ConnectingQueue(); |
| 59 queue->push_back(job); | 50 queue->push_back(job); |
| 60 addr_map_[addrkey] = queue; | 51 addr_map_[address] = queue; |
| 61 } else { | 52 } else { |
| 62 iter->second->push_back(job); | 53 iter->second->push_back(job); |
| 63 job->SetWaiting(); | 54 job->SetWaiting(); |
| 64 DVLOG(1) << "Waiting on " << addrkey; | 55 DVLOG(1) << "Waiting on " << address.ToString(); |
| 65 } | 56 } |
| 66 } | 57 } |
| 67 } | 58 } |
| 68 | 59 |
| 69 void WebSocketThrottle::RemoveFromQueue(WebSocketJob* job) { | 60 void WebSocketThrottle::RemoveFromQueue(WebSocketJob* job) { |
| 70 bool in_queue = false; | 61 ConnectingQueue::iterator queue_iter = |
| 71 for (ConnectingQueue::iterator iter = queue_.begin(); | 62 std::find(queue_.begin(), queue_.end(), job); |
| 72 iter != queue_.end(); | 63 if (queue_iter == queue_.end()) |
| 73 ++iter) { | |
| 74 if (*iter == job) { | |
| 75 queue_.erase(iter); | |
| 76 in_queue = true; | |
| 77 break; | |
| 78 } | |
| 79 } | |
| 80 if (!in_queue) | |
| 81 return; | 64 return; |
| 65 queue_.erase(queue_iter); |
| 82 const AddressList& address_list = job->address_list(); | 66 const AddressList& address_list = job->address_list(); |
| 83 base::hash_set<std::string> address_set; | 67 std::set<IPEndPoint> address_set; |
| 84 for (AddressList::const_iterator addr_iter = address_list.begin(); | 68 for (AddressList::const_iterator addr_iter = address_list.begin(); |
| 85 addr_iter != address_list.end(); | 69 addr_iter != address_list.end(); |
| 86 ++addr_iter) { | 70 ++addr_iter) { |
| 87 std::string addrkey = IPEndPointToHashkey(*addr_iter); | 71 const IPEndPoint& address = *addr_iter; |
| 88 // If |addrkey| is already processed, don't do it again. | 72 // If |address| is already processed, don't do it again. |
| 89 if (address_set.find(addrkey) != address_set.end()) | 73 if (!address_set.insert(address).second) |
| 90 continue; | 74 continue; |
| 91 address_set.insert(addrkey); | |
| 92 | 75 |
| 93 ConnectingAddressMap::iterator iter = addr_map_.find(addrkey); | 76 ConnectingAddressMap::iterator map_iter = addr_map_.find(address); |
| 94 DCHECK(iter != addr_map_.end()); | 77 DCHECK(map_iter != addr_map_.end()); |
| 95 | 78 |
| 96 ConnectingQueue* queue = iter->second; | 79 ConnectingQueue* queue = map_iter->second; |
| 97 // Job may not be front of queue when job is closed early while waiting. | 80 // Job may not be front of queue if the socket is closed while waiting. |
| 98 for (ConnectingQueue::iterator iter = queue->begin(); | 81 ConnectingQueue::iterator address_queue_iter = |
| 99 iter != queue->end(); | 82 std::find(queue->begin(), queue->end(), job); |
| 100 ++iter) { | 83 if (address_queue_iter != queue->end()) |
| 101 if (*iter == job) { | 84 queue->erase(address_queue_iter); |
| 102 queue->erase(iter); | |
| 103 break; | |
| 104 } | |
| 105 } | |
| 106 if (queue->empty()) { | 85 if (queue->empty()) { |
| 107 delete queue; | 86 delete queue; |
| 108 addr_map_.erase(iter); | 87 addr_map_.erase(map_iter); |
| 109 } | 88 } |
| 110 } | 89 } |
| 111 } | 90 } |
| 112 | 91 |
| 113 void WebSocketThrottle::WakeupSocketIfNecessary() { | 92 void WebSocketThrottle::WakeupSocketIfNecessary() { |
| 114 for (ConnectingQueue::iterator iter = queue_.begin(); | 93 for (ConnectingQueue::iterator iter = queue_.begin(); |
| 115 iter != queue_.end(); | 94 iter != queue_.end(); |
| 116 ++iter) { | 95 ++iter) { |
| 117 WebSocketJob* job = *iter; | 96 WebSocketJob* job = *iter; |
| 118 if (!job->IsWaiting()) | 97 if (!job->IsWaiting()) |
| 119 continue; | 98 continue; |
| 120 | 99 |
| 121 bool should_wakeup = true; | 100 bool should_wakeup = true; |
| 122 const AddressList& address_list = job->address_list(); | 101 const AddressList& address_list = job->address_list(); |
| 123 for (AddressList::const_iterator addr_iter = address_list.begin(); | 102 for (AddressList::const_iterator addr_iter = address_list.begin(); |
| 124 addr_iter != address_list.end(); | 103 addr_iter != address_list.end(); |
| 125 ++addr_iter) { | 104 ++addr_iter) { |
| 126 std::string addrkey = IPEndPointToHashkey(*addr_iter); | 105 const IPEndPoint& address = *addr_iter; |
| 127 ConnectingAddressMap::iterator iter = addr_map_.find(addrkey); | 106 ConnectingAddressMap::iterator map_iter = addr_map_.find(address); |
| 128 DCHECK(iter != addr_map_.end()); | 107 DCHECK(map_iter != addr_map_.end()); |
| 129 ConnectingQueue* queue = iter->second; | 108 ConnectingQueue* queue = map_iter->second; |
| 130 if (job != queue->front()) { | 109 if (job != queue->front()) { |
| 131 should_wakeup = false; | 110 should_wakeup = false; |
| 132 break; | 111 break; |
| 133 } | 112 } |
| 134 } | 113 } |
| 135 if (should_wakeup) | 114 if (should_wakeup) |
| 136 job->Wakeup(); | 115 job->Wakeup(); |
| 137 } | 116 } |
| 138 } | 117 } |
| 139 | 118 |
| 140 } // namespace net | 119 } // namespace net |
| OLD | NEW |