1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be 3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/websockets/websocket_throttle.h" 6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <string> 8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/hash_tables.h" 10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/ref_counted.h" 11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/singleton.h" 12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/message_loop.h" 133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h" 14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h" 153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/stringprintf.h" 16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/io_buffer.h" 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/sys_addrinfo.h" 18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/socket_stream/socket_stream.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/websockets/websocket_job.h" 20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net { 22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic std::string AddrinfoToHashkey(const struct addrinfo* addrinfo) { 24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott switch (addrinfo->ai_family) { 25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott case AF_INET: { 26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const struct sockaddr_in* const addr = 27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott reinterpret_cast<const sockaddr_in*>(addrinfo->ai_addr); 283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return base::StringPrintf("%d:%s", 293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick addrinfo->ai_family, 303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick base::HexEncode(&addr->sin_addr, 4).c_str()); 31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott case AF_INET6: { 33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const struct sockaddr_in6* const addr6 = 34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott reinterpret_cast<const sockaddr_in6*>(addrinfo->ai_addr); 353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return base::StringPrintf( 363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick "%d:%s", 373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick addrinfo->ai_family, 383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick base::HexEncode(&addr6->sin6_addr, 393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick sizeof(addr6->sin6_addr)).c_str()); 40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott default: 423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return base::StringPrintf("%d:%s", 433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick addrinfo->ai_family, 443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick base::HexEncode(addrinfo->ai_addr, 453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick addrinfo->ai_addrlen).c_str()); 46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottWebSocketThrottle::WebSocketThrottle() { 50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottWebSocketThrottle::~WebSocketThrottle() { 53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(queue_.empty()); 54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(addr_map_.empty()); 55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 5721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// static 5821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenWebSocketThrottle* WebSocketThrottle::GetInstance() { 5921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return Singleton<WebSocketThrottle>::get(); 6021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen} 6121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketThrottle::PutInQueue(WebSocketJob* job) { 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch queue_.push_back(job); 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const AddressList& address_list = job->address_list(); 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::hash_set<std::string> address_set; 66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (const struct addrinfo* addrinfo = address_list.head(); 67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott addrinfo != NULL; 68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott addrinfo = addrinfo->ai_next) { 69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string addrkey = AddrinfoToHashkey(addrinfo); 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If |addrkey| is already processed, don't do it again. 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (address_set.find(addrkey) != address_set.end()) 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch address_set.insert(addrkey); 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ConnectingAddressMap::iterator iter = addr_map_.find(addrkey); 77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (iter == addr_map_.end()) { 78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ConnectingQueue* queue = new ConnectingQueue(); 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch queue->push_back(job); 80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott addr_map_[addrkey] = queue; 81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else { 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch iter->second->push_back(job); 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch job->SetWaiting(); 84731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DVLOG(1) << "Waiting on " << addrkey; 85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketThrottle::RemoveFromQueue(WebSocketJob* job) { 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool in_queue = false; 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (ConnectingQueue::iterator iter = queue_.begin(); 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch iter != queue_.end(); 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++iter) { 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (*iter == job) { 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch queue_.erase(iter); 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch in_queue = true; 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!in_queue) 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const AddressList& address_list = job->address_list(); 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::hash_set<std::string> address_set; 104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (const struct addrinfo* addrinfo = address_list.head(); 105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott addrinfo != NULL; 106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott addrinfo = addrinfo->ai_next) { 107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string addrkey = AddrinfoToHashkey(addrinfo); 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If |addrkey| is already processed, don't do it again. 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (address_set.find(addrkey) != address_set.end()) 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch address_set.insert(addrkey); 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ConnectingAddressMap::iterator iter = addr_map_.find(addrkey); 114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(iter != addr_map_.end()); 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ConnectingQueue* queue = iter->second; 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Job may not be front of queue when job is closed early while waiting. 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (ConnectingQueue::iterator iter = queue->begin(); 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch iter != queue->end(); 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++iter) { 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (*iter == job) { 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch queue->erase(iter); 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (queue->empty()) { 127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott delete queue; 128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott addr_map_.erase(iter); 129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WebSocketThrottle::WakeupSocketIfNecessary() { 134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (ConnectingQueue::iterator iter = queue_.begin(); 135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott iter != queue_.end(); 136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ++iter) { 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WebSocketJob* job = *iter; 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!job->IsWaiting()) 139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott continue; 140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott bool should_wakeup = true; 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const AddressList& address_list = job->address_list(); 143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (const struct addrinfo* addrinfo = address_list.head(); 144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott addrinfo != NULL; 145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott addrinfo = addrinfo->ai_next) { 146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string addrkey = AddrinfoToHashkey(addrinfo); 147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ConnectingAddressMap::iterator iter = addr_map_.find(addrkey); 148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(iter != addr_map_.end()); 149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ConnectingQueue* queue = iter->second; 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (job != queue->front()) { 151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott should_wakeup = false; 152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott break; 153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (should_wakeup) 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch job->Wakeup(); 157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} // namespace net 161