blob: c714de6bf46a21ced135be98d24409683e90cc4b [file] [log] [blame]
[email protected]b30a3f52010-10-16 01:05:461// Copyright (c) 2010 The Chromium Authors. All rights reserved.
[email protected]4c4eac02009-11-04 10:02:282// 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/websockets/websocket_throttle.h"
6
[email protected]4c4eac02009-11-04 10:02:287#include <string>
8
[email protected]10821128c2010-04-21 06:50:539#include "base/hash_tables.h"
[email protected]4c4eac02009-11-04 10:02:2810#include "base/message_loop.h"
11#include "base/ref_counted.h"
12#include "base/singleton.h"
[email protected]e83326f2010-07-31 17:29:2513#include "base/string_number_conversions.h"
[email protected]ea372492010-07-31 18:21:0514#include "base/string_util.h"
[email protected]d8eb84242010-09-25 02:25:0615#include "base/stringprintf.h"
[email protected]4c4eac02009-11-04 10:02:2816#include "net/base/io_buffer.h"
[email protected]a540c2d2009-12-12 00:47:3717#include "net/base/sys_addrinfo.h"
[email protected]4c4eac02009-11-04 10:02:2818#include "net/socket_stream/socket_stream.h"
[email protected]b4384a7982010-03-17 07:29:5419#include "net/websockets/websocket_job.h"
[email protected]4c4eac02009-11-04 10:02:2820
21namespace net {
22
23static std::string AddrinfoToHashkey(const struct addrinfo* addrinfo) {
24 switch (addrinfo->ai_family) {
25 case AF_INET: {
26 const struct sockaddr_in* const addr =
27 reinterpret_cast<const sockaddr_in*>(addrinfo->ai_addr);
[email protected]d8eb84242010-09-25 02:25:0628 return base::StringPrintf("%d:%s",
29 addrinfo->ai_family,
30 base::HexEncode(&addr->sin_addr, 4).c_str());
[email protected]4c4eac02009-11-04 10:02:2831 }
32 case AF_INET6: {
33 const struct sockaddr_in6* const addr6 =
34 reinterpret_cast<const sockaddr_in6*>(addrinfo->ai_addr);
[email protected]d8eb84242010-09-25 02:25:0635 return base::StringPrintf(
36 "%d:%s",
37 addrinfo->ai_family,
38 base::HexEncode(&addr6->sin6_addr,
39 sizeof(addr6->sin6_addr)).c_str());
[email protected]4c4eac02009-11-04 10:02:2840 }
41 default:
[email protected]d8eb84242010-09-25 02:25:0642 return base::StringPrintf("%d:%s",
43 addrinfo->ai_family,
44 base::HexEncode(addrinfo->ai_addr,
45 addrinfo->ai_addrlen).c_str());
[email protected]4c4eac02009-11-04 10:02:2846 }
47}
48
[email protected]4c4eac02009-11-04 10:02:2849WebSocketThrottle::WebSocketThrottle() {
[email protected]4c4eac02009-11-04 10:02:2850}
51
52WebSocketThrottle::~WebSocketThrottle() {
53 DCHECK(queue_.empty());
54 DCHECK(addr_map_.empty());
55}
56
[email protected]ee166792010-12-09 08:14:1057// static
58WebSocketThrottle* WebSocketThrottle::GetInstance() {
59 return Singleton<WebSocketThrottle>::get();
60}
61
[email protected]b4384a7982010-03-17 07:29:5462void WebSocketThrottle::PutInQueue(WebSocketJob* job) {
63 queue_.push_back(job);
64 const AddressList& address_list = job->address_list();
[email protected]10821128c2010-04-21 06:50:5365 base::hash_set<std::string> address_set;
[email protected]4c4eac02009-11-04 10:02:2866 for (const struct addrinfo* addrinfo = address_list.head();
67 addrinfo != NULL;
68 addrinfo = addrinfo->ai_next) {
69 std::string addrkey = AddrinfoToHashkey(addrinfo);
[email protected]10821128c2010-04-21 06:50:5370
71 // If |addrkey| is already processed, don't do it again.
72 if (address_set.find(addrkey) != address_set.end())
73 continue;
74 address_set.insert(addrkey);
75
[email protected]4c4eac02009-11-04 10:02:2876 ConnectingAddressMap::iterator iter = addr_map_.find(addrkey);
77 if (iter == addr_map_.end()) {
78 ConnectingQueue* queue = new ConnectingQueue();
[email protected]b4384a7982010-03-17 07:29:5479 queue->push_back(job);
[email protected]4c4eac02009-11-04 10:02:2880 addr_map_[addrkey] = queue;
81 } else {
[email protected]b4384a7982010-03-17 07:29:5482 iter->second->push_back(job);
83 job->SetWaiting();
[email protected]b30a3f52010-10-16 01:05:4684 DVLOG(1) << "Waiting on " << addrkey;
[email protected]4c4eac02009-11-04 10:02:2885 }
86 }
87}
88
[email protected]b4384a7982010-03-17 07:29:5489void WebSocketThrottle::RemoveFromQueue(WebSocketJob* job) {
90 bool in_queue = false;
91 for (ConnectingQueue::iterator iter = queue_.begin();
92 iter != queue_.end();
93 ++iter) {
94 if (*iter == job) {
95 queue_.erase(iter);
96 in_queue = true;
97 break;
98 }
99 }
100 if (!in_queue)
101 return;
102 const AddressList& address_list = job->address_list();
[email protected]10821128c2010-04-21 06:50:53103 base::hash_set<std::string> address_set;
[email protected]4c4eac02009-11-04 10:02:28104 for (const struct addrinfo* addrinfo = address_list.head();
105 addrinfo != NULL;
106 addrinfo = addrinfo->ai_next) {
107 std::string addrkey = AddrinfoToHashkey(addrinfo);
[email protected]10821128c2010-04-21 06:50:53108 // If |addrkey| is already processed, don't do it again.
109 if (address_set.find(addrkey) != address_set.end())
110 continue;
111 address_set.insert(addrkey);
112
[email protected]4c4eac02009-11-04 10:02:28113 ConnectingAddressMap::iterator iter = addr_map_.find(addrkey);
114 DCHECK(iter != addr_map_.end());
[email protected]10821128c2010-04-21 06:50:53115
[email protected]4c4eac02009-11-04 10:02:28116 ConnectingQueue* queue = iter->second;
[email protected]b4384a7982010-03-17 07:29:54117 // Job may not be front of queue when job is closed early while waiting.
118 for (ConnectingQueue::iterator iter = queue->begin();
119 iter != queue->end();
120 ++iter) {
121 if (*iter == job) {
122 queue->erase(iter);
123 break;
124 }
125 }
[email protected]a6cf2a3e2009-11-04 11:04:40126 if (queue->empty()) {
127 delete queue;
[email protected]4c4eac02009-11-04 10:02:28128 addr_map_.erase(iter);
[email protected]a6cf2a3e2009-11-04 11:04:40129 }
[email protected]4c4eac02009-11-04 10:02:28130 }
[email protected]4c4eac02009-11-04 10:02:28131}
132
133void WebSocketThrottle::WakeupSocketIfNecessary() {
134 for (ConnectingQueue::iterator iter = queue_.begin();
135 iter != queue_.end();
136 ++iter) {
[email protected]b4384a7982010-03-17 07:29:54137 WebSocketJob* job = *iter;
138 if (!job->IsWaiting())
[email protected]4c4eac02009-11-04 10:02:28139 continue;
140
141 bool should_wakeup = true;
[email protected]b4384a7982010-03-17 07:29:54142 const AddressList& address_list = job->address_list();
[email protected]4c4eac02009-11-04 10:02:28143 for (const struct addrinfo* addrinfo = address_list.head();
144 addrinfo != NULL;
145 addrinfo = addrinfo->ai_next) {
146 std::string addrkey = AddrinfoToHashkey(addrinfo);
147 ConnectingAddressMap::iterator iter = addr_map_.find(addrkey);
148 DCHECK(iter != addr_map_.end());
149 ConnectingQueue* queue = iter->second;
[email protected]b4384a7982010-03-17 07:29:54150 if (job != queue->front()) {
[email protected]4c4eac02009-11-04 10:02:28151 should_wakeup = false;
152 break;
153 }
154 }
155 if (should_wakeup)
[email protected]b4384a7982010-03-17 07:29:54156 job->Wakeup();
[email protected]4c4eac02009-11-04 10:02:28157 }
158}
159
[email protected]4c4eac02009-11-04 10:02:28160} // namespace net