websocket_throttle.cc revision ddb351dbec246cf1fab5ec20d2d5520909041de1
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