OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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/base/tcp_client_socket_pool.h" | 5 #include "net/base/tcp_client_socket_pool.h" |
6 | 6 |
7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
8 #include "base/field_trial.h" | 8 #include "base/field_trial.h" |
9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
10 #include "base/time.h" | 10 #include "base/time.h" |
(...skipping 27 matching lines...) Expand all Loading... |
38 const ClientSocketHandle* handle, | 38 const ClientSocketHandle* handle, |
39 ClientSocketFactory* client_socket_factory, | 39 ClientSocketFactory* client_socket_factory, |
40 TCPClientSocketPool* pool) | 40 TCPClientSocketPool* pool) |
41 : group_name_(group_name), | 41 : group_name_(group_name), |
42 handle_(handle), | 42 handle_(handle), |
43 client_socket_factory_(client_socket_factory), | 43 client_socket_factory_(client_socket_factory), |
44 ALLOW_THIS_IN_INITIALIZER_LIST( | 44 ALLOW_THIS_IN_INITIALIZER_LIST( |
45 callback_(this, | 45 callback_(this, |
46 &TCPClientSocketPool::ConnectingSocket::OnIOComplete)), | 46 &TCPClientSocketPool::ConnectingSocket::OnIOComplete)), |
47 pool_(pool), | 47 pool_(pool), |
48 resolver_(pool->GetHostResolver()), | 48 resolver_(pool->GetHostResolver()) {} |
49 canceled_(false) { | |
50 CHECK(!ContainsKey(pool_->connecting_socket_map_, handle)); | |
51 pool_->connecting_socket_map_[handle] = this; | |
52 } | |
53 | 49 |
54 TCPClientSocketPool::ConnectingSocket::~ConnectingSocket() { | 50 TCPClientSocketPool::ConnectingSocket::~ConnectingSocket() { |
55 if (!canceled_) | 51 // We don't worry about cancelling the host resolution and TCP connect, since |
56 pool_->connecting_socket_map_.erase(handle_); | 52 // ~SingleRequestHostResolver and ~ClientSocket will take care of it. |
57 } | 53 } |
58 | 54 |
59 int TCPClientSocketPool::ConnectingSocket::Connect( | 55 int TCPClientSocketPool::ConnectingSocket::Connect( |
60 const HostResolver::RequestInfo& resolve_info) { | 56 const HostResolver::RequestInfo& resolve_info) { |
61 CHECK(!canceled_); | |
62 int rv = resolver_.Resolve(resolve_info, &addresses_, &callback_); | 57 int rv = resolver_.Resolve(resolve_info, &addresses_, &callback_); |
63 if (rv != ERR_IO_PENDING) | 58 if (rv != ERR_IO_PENDING) |
64 rv = OnIOCompleteInternal(rv, true /* synchronous */); | 59 rv = OnIOCompleteInternal(rv, true /* synchronous */); |
65 return rv; | 60 return rv; |
66 } | 61 } |
67 | 62 |
68 void TCPClientSocketPool::ConnectingSocket::OnIOComplete(int result) { | 63 void TCPClientSocketPool::ConnectingSocket::OnIOComplete(int result) { |
69 OnIOCompleteInternal(result, false /* asynchronous */); | 64 OnIOCompleteInternal(result, false /* asynchronous */); |
70 } | 65 } |
71 | 66 |
72 int TCPClientSocketPool::ConnectingSocket::OnIOCompleteInternal( | 67 int TCPClientSocketPool::ConnectingSocket::OnIOCompleteInternal( |
73 int result, bool synchronous) { | 68 int result, bool synchronous) { |
74 CHECK(result != ERR_IO_PENDING); | 69 CHECK(result != ERR_IO_PENDING); |
75 | 70 |
76 if (canceled_) { | |
77 // We got canceled, so bail out. | |
78 delete this; | |
79 return result; | |
80 } | |
81 | |
82 GroupMap::iterator group_it = pool_->group_map_.find(group_name_); | 71 GroupMap::iterator group_it = pool_->group_map_.find(group_name_); |
83 if (group_it == pool_->group_map_.end()) { | 72 CHECK(group_it != pool_->group_map_.end()); |
84 // The request corresponding to this ConnectingSocket has been canceled. | |
85 // Stop bothering with it. | |
86 delete this; | |
87 return result; | |
88 } | |
89 | 73 |
90 Group& group = group_it->second; | 74 Group& group = group_it->second; |
91 | 75 |
92 RequestMap* request_map = &group.connecting_requests; | 76 RequestMap* request_map = &group.connecting_requests; |
93 RequestMap::iterator it = request_map->find(handle_); | 77 RequestMap::iterator it = request_map->find(handle_); |
94 if (it == request_map->end()) { | 78 CHECK(it != request_map->end()); |
95 // The request corresponding to this ConnectingSocket has been canceled. | |
96 // Stop bothering with it. | |
97 delete this; | |
98 return result; | |
99 } | |
100 | 79 |
101 if (result == OK && it->second.load_state == LOAD_STATE_RESOLVING_HOST) { | 80 if (result == OK && it->second.load_state == LOAD_STATE_RESOLVING_HOST) { |
102 it->second.load_state = LOAD_STATE_CONNECTING; | 81 it->second.load_state = LOAD_STATE_CONNECTING; |
103 socket_.reset(client_socket_factory_->CreateTCPClientSocket(addresses_)); | 82 socket_.reset(client_socket_factory_->CreateTCPClientSocket(addresses_)); |
104 connect_start_time_ = base::Time::Now(); | 83 connect_start_time_ = base::Time::Now(); |
105 result = socket_->Connect(&callback_); | 84 result = socket_->Connect(&callback_); |
106 if (result == ERR_IO_PENDING) | 85 if (result == ERR_IO_PENDING) |
107 return result; | 86 return result; |
108 } | 87 } |
109 | 88 |
110 if (result == OK) { | 89 if (result == OK) { |
| 90 CHECK(it->second.load_state == LOAD_STATE_CONNECTING); |
111 CHECK(connect_start_time_ != base::Time()); | 91 CHECK(connect_start_time_ != base::Time()); |
112 base::TimeDelta connect_duration = | 92 base::TimeDelta connect_duration = |
113 base::Time::Now() - connect_start_time_; | 93 base::Time::Now() - connect_start_time_; |
114 | 94 |
115 UMA_HISTOGRAM_CLIPPED_TIMES("Net.TCP_Connection_Latency", | 95 UMA_HISTOGRAM_CLIPPED_TIMES("Net.TCP_Connection_Latency", |
116 connect_duration, | 96 connect_duration, |
117 base::TimeDelta::FromMilliseconds(1), | 97 base::TimeDelta::FromMilliseconds(1), |
118 base::TimeDelta::FromMinutes(10), | 98 base::TimeDelta::FromMinutes(10), |
119 100); | 99 100); |
120 } | 100 } |
(...skipping 13 matching lines...) Expand all Loading... |
134 // Delete group if no longer needed. | 114 // Delete group if no longer needed. |
135 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { | 115 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { |
136 CHECK(group.pending_requests.empty()); | 116 CHECK(group.pending_requests.empty()); |
137 CHECK(group.connecting_requests.empty()); | 117 CHECK(group.connecting_requests.empty()); |
138 pool_->group_map_.erase(group_it); | 118 pool_->group_map_.erase(group_it); |
139 } | 119 } |
140 } | 120 } |
141 | 121 |
142 if (!synchronous) | 122 if (!synchronous) |
143 request.callback->Run(result); | 123 request.callback->Run(result); |
144 delete this; | 124 pool_->RemoveConnectingSocket(handle_); // will delete |this|. |
145 return result; | 125 return result; |
146 } | 126 } |
147 | 127 |
148 void TCPClientSocketPool::ConnectingSocket::Cancel() { | |
149 CHECK(!canceled_); | |
150 CHECK(ContainsKey(pool_->connecting_socket_map_, handle_)); | |
151 pool_->connecting_socket_map_.erase(handle_); | |
152 canceled_ = true; | |
153 } | |
154 | |
155 TCPClientSocketPool::TCPClientSocketPool( | 128 TCPClientSocketPool::TCPClientSocketPool( |
156 int max_sockets_per_group, | 129 int max_sockets_per_group, |
157 HostResolver* host_resolver, | 130 HostResolver* host_resolver, |
158 ClientSocketFactory* client_socket_factory) | 131 ClientSocketFactory* client_socket_factory) |
159 : client_socket_factory_(client_socket_factory), | 132 : client_socket_factory_(client_socket_factory), |
160 idle_socket_count_(0), | 133 idle_socket_count_(0), |
161 max_sockets_per_group_(max_sockets_per_group), | 134 max_sockets_per_group_(max_sockets_per_group), |
162 host_resolver_(host_resolver) { | 135 host_resolver_(host_resolver) { |
163 } | 136 } |
164 | 137 |
165 TCPClientSocketPool::~TCPClientSocketPool() { | 138 TCPClientSocketPool::~TCPClientSocketPool() { |
166 // Clean up any idle sockets. Assert that we have no remaining active | 139 // Clean up any idle sockets. Assert that we have no remaining active |
167 // sockets or pending requests. They should have all been cleaned up prior | 140 // sockets or pending requests. They should have all been cleaned up prior |
168 // to the manager being destroyed. | 141 // to the manager being destroyed. |
169 CloseIdleSockets(); | 142 CloseIdleSockets(); |
170 DCHECK(group_map_.empty()); | 143 DCHECK(group_map_.empty()); |
| 144 DCHECK(connecting_socket_map_.empty()); |
171 } | 145 } |
172 | 146 |
173 // InsertRequestIntoQueue inserts the request into the queue based on | 147 // InsertRequestIntoQueue inserts the request into the queue based on |
174 // priority. Highest priorities are closest to the front. Older requests are | 148 // priority. Highest priorities are closest to the front. Older requests are |
175 // prioritized over requests of equal priority. | 149 // prioritized over requests of equal priority. |
176 // | 150 // |
177 // static | 151 // static |
178 void TCPClientSocketPool::InsertRequestIntoQueue( | 152 void TCPClientSocketPool::InsertRequestIntoQueue( |
179 const Request& r, RequestQueue* pending_requests) { | 153 const Request& r, RequestQueue* pending_requests) { |
180 RequestQueue::iterator it = pending_requests->begin(); | 154 RequestQueue::iterator it = pending_requests->begin(); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
212 // We found one we can reuse! | 186 // We found one we can reuse! |
213 handle->set_socket(idle_socket.socket); | 187 handle->set_socket(idle_socket.socket); |
214 handle->set_is_reused(true); | 188 handle->set_is_reused(true); |
215 return OK; | 189 return OK; |
216 } | 190 } |
217 delete idle_socket.socket; | 191 delete idle_socket.socket; |
218 } | 192 } |
219 | 193 |
220 // We couldn't find a socket to reuse, so allocate and connect a new one. | 194 // We couldn't find a socket to reuse, so allocate and connect a new one. |
221 | 195 |
222 // First, we need to make sure we aren't already servicing a request for this | |
223 // handle (which could happen if we requested, canceled, and then requested | |
224 // with the same handle). | |
225 if (ContainsKey(connecting_socket_map_, handle)) | |
226 connecting_socket_map_[handle]->Cancel(); | |
227 | |
228 CHECK(callback); | 196 CHECK(callback); |
229 Request r(handle, callback, priority, resolve_info, | 197 Request r(handle, callback, priority, resolve_info, |
230 LOAD_STATE_RESOLVING_HOST); | 198 LOAD_STATE_RESOLVING_HOST); |
231 group_map_[group_name].connecting_requests[handle] = r; | 199 group_map_[group_name].connecting_requests[handle] = r; |
232 | 200 |
233 // connecting_socket will delete itself. | 201 CHECK(!ContainsKey(connecting_socket_map_, handle)); |
| 202 |
234 ConnectingSocket* connecting_socket = | 203 ConnectingSocket* connecting_socket = |
235 new ConnectingSocket(group_name, handle, client_socket_factory_, this); | 204 new ConnectingSocket(group_name, handle, client_socket_factory_, this); |
| 205 connecting_socket_map_[handle] = connecting_socket; |
236 int rv = connecting_socket->Connect(resolve_info); | 206 int rv = connecting_socket->Connect(resolve_info); |
237 return rv; | 207 return rv; |
238 } | 208 } |
239 | 209 |
240 void TCPClientSocketPool::CancelRequest(const std::string& group_name, | 210 void TCPClientSocketPool::CancelRequest(const std::string& group_name, |
241 const ClientSocketHandle* handle) { | 211 const ClientSocketHandle* handle) { |
242 CHECK(ContainsKey(group_map_, group_name)); | 212 CHECK(ContainsKey(group_map_, group_name)); |
243 | 213 |
244 Group& group = group_map_[group_name]; | 214 Group& group = group_map_[group_name]; |
245 | 215 |
246 // Search pending_requests for matching handle. | 216 // Search pending_requests for matching handle. |
247 RequestQueue::iterator it = group.pending_requests.begin(); | 217 RequestQueue::iterator it = group.pending_requests.begin(); |
248 for (; it != group.pending_requests.end(); ++it) { | 218 for (; it != group.pending_requests.end(); ++it) { |
249 if (it->handle == handle) { | 219 if (it->handle == handle) { |
250 group.pending_requests.erase(it); | 220 group.pending_requests.erase(it); |
251 return; | 221 return; |
252 } | 222 } |
253 } | 223 } |
254 | 224 |
255 // It's invalid to cancel a non-existent request. | 225 // It's invalid to cancel a non-existent request. |
256 CHECK(ContainsKey(group.connecting_requests, handle)); | 226 CHECK(ContainsKey(group.connecting_requests, handle)); |
257 | 227 |
258 RequestMap::iterator map_it = group.connecting_requests.find(handle); | 228 RequestMap::iterator map_it = group.connecting_requests.find(handle); |
259 if (map_it != group.connecting_requests.end()) { | 229 if (map_it != group.connecting_requests.end()) { |
| 230 RemoveConnectingSocket(handle); |
| 231 |
260 group.connecting_requests.erase(map_it); | 232 group.connecting_requests.erase(map_it); |
261 group.active_socket_count--; | 233 group.active_socket_count--; |
262 | 234 |
263 // Delete group if no longer needed. | 235 // Delete group if no longer needed. |
264 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { | 236 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { |
265 CHECK(group.pending_requests.empty()); | 237 CHECK(group.pending_requests.empty()); |
266 CHECK(group.connecting_requests.empty()); | 238 CHECK(group.connecting_requests.empty()); |
267 group_map_.erase(group_name); | 239 group_map_.erase(group_name); |
268 } | 240 } |
269 } | 241 } |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
412 } | 384 } |
413 | 385 |
414 // Delete group if no longer needed. | 386 // Delete group if no longer needed. |
415 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { | 387 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { |
416 CHECK(group.pending_requests.empty()); | 388 CHECK(group.pending_requests.empty()); |
417 CHECK(group.connecting_requests.empty()); | 389 CHECK(group.connecting_requests.empty()); |
418 group_map_.erase(i); | 390 group_map_.erase(i); |
419 } | 391 } |
420 } | 392 } |
421 | 393 |
| 394 void TCPClientSocketPool::RemoveConnectingSocket( |
| 395 const ClientSocketHandle* handle) { |
| 396 ConnectingSocketMap::iterator it = connecting_socket_map_.find(handle); |
| 397 CHECK(it != connecting_socket_map_.end()); |
| 398 delete it->second; |
| 399 connecting_socket_map_.erase(it); |
| 400 } |
| 401 |
422 } // namespace net | 402 } // namespace net |
OLD | NEW |