OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/socket/tcp_client_socket.h" | 5 #include "net/socket/tcp_client_socket.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/metrics/histogram_macros.h" | 11 #include "base/metrics/histogram_macros.h" |
12 #include "base/profiler/scoped_tracker.h" | 12 #include "base/profiler/scoped_tracker.h" |
13 #include "base/time/time.h" | 13 #include "base/time/time.h" |
14 #include "net/base/io_buffer.h" | 14 #include "net/base/io_buffer.h" |
15 #include "net/base/ip_endpoint.h" | 15 #include "net/base/ip_endpoint.h" |
16 #include "net/base/net_errors.h" | 16 #include "net/base/net_errors.h" |
17 #include "net/socket/socket_performance_watcher.h" | 17 #include "net/socket/socket_performance_watcher.h" |
18 | 18 |
| 19 #if !defined(OS_NACL) |
| 20 #include "base/power_monitor/power_monitor.h" |
| 21 #endif |
| 22 |
19 namespace net { | 23 namespace net { |
20 | 24 |
21 class NetLogWithSource; | 25 class NetLogWithSource; |
22 | 26 |
23 TCPClientSocket::TCPClientSocket( | 27 TCPClientSocket::TCPClientSocket( |
24 const AddressList& addresses, | 28 const AddressList& addresses, |
25 std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher, | 29 std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher, |
26 net::NetLog* net_log, | 30 net::NetLog* net_log, |
27 const net::NetLogSource& source) | 31 const net::NetLogSource& source) |
28 : socket_performance_watcher_(socket_performance_watcher.get()), | 32 : socket_performance_watcher_(socket_performance_watcher.get()), |
29 socket_(new TCPSocket(std::move(socket_performance_watcher), | 33 socket_(new TCPSocket(std::move(socket_performance_watcher), |
30 net_log, | 34 net_log, |
31 source)), | 35 source)), |
32 addresses_(addresses), | 36 addresses_(addresses), |
33 current_address_index_(-1), | 37 current_address_index_(-1), |
34 next_connect_state_(CONNECT_STATE_NONE), | 38 next_connect_state_(CONNECT_STATE_NONE), |
35 previously_disconnected_(false), | 39 previously_disconnected_(false), |
36 total_received_bytes_(0) {} | 40 total_received_bytes_(0), |
| 41 weak_ptr_factory_(this) {} |
37 | 42 |
38 TCPClientSocket::TCPClientSocket(std::unique_ptr<TCPSocket> connected_socket, | 43 TCPClientSocket::TCPClientSocket(std::unique_ptr<TCPSocket> connected_socket, |
39 const IPEndPoint& peer_address) | 44 const IPEndPoint& peer_address) |
40 : socket_performance_watcher_(nullptr), | 45 : socket_performance_watcher_(nullptr), |
41 socket_(std::move(connected_socket)), | 46 socket_(std::move(connected_socket)), |
42 addresses_(AddressList(peer_address)), | 47 addresses_(AddressList(peer_address)), |
43 current_address_index_(0), | 48 current_address_index_(0), |
44 next_connect_state_(CONNECT_STATE_NONE), | 49 next_connect_state_(CONNECT_STATE_NONE), |
45 previously_disconnected_(false), | 50 previously_disconnected_(false), |
46 total_received_bytes_(0) { | 51 total_received_bytes_(0), |
| 52 weak_ptr_factory_(this) { |
47 DCHECK(socket_); | 53 DCHECK(socket_); |
48 | 54 |
49 socket_->SetDefaultOptionsForClient(); | 55 socket_->SetDefaultOptionsForClient(); |
50 use_history_.set_was_ever_connected(); | 56 use_history_.set_was_ever_connected(); |
51 } | 57 } |
52 | 58 |
53 TCPClientSocket::~TCPClientSocket() { | 59 TCPClientSocket::~TCPClientSocket() { |
| 60 SetFailOnSuspend(false); |
54 Disconnect(); | 61 Disconnect(); |
55 } | 62 } |
56 | 63 |
57 int TCPClientSocket::Bind(const IPEndPoint& address) { | 64 int TCPClientSocket::Bind(const IPEndPoint& address) { |
58 if (current_address_index_ >= 0 || bind_address_) { | 65 if (current_address_index_ >= 0 || bind_address_) { |
59 // Cannot bind the socket if we are already connected or connecting. | 66 // Cannot bind the socket if we are already connected or connecting. |
60 NOTREACHED(); | 67 NOTREACHED(); |
61 return ERR_UNEXPECTED; | 68 return ERR_UNEXPECTED; |
62 } | 69 } |
63 | 70 |
(...skipping 12 matching lines...) Expand all Loading... |
76 return OK; | 83 return OK; |
77 } | 84 } |
78 | 85 |
79 int TCPClientSocket::Connect(const CompletionCallback& callback) { | 86 int TCPClientSocket::Connect(const CompletionCallback& callback) { |
80 DCHECK(!callback.is_null()); | 87 DCHECK(!callback.is_null()); |
81 | 88 |
82 // If connecting or already connected, then just return OK. | 89 // If connecting or already connected, then just return OK. |
83 if (socket_->IsValid() && current_address_index_ >= 0) | 90 if (socket_->IsValid() && current_address_index_ >= 0) |
84 return OK; | 91 return OK; |
85 | 92 |
| 93 was_disconnected_on_suspend_ = false; |
| 94 |
86 socket_->StartLoggingMultipleConnectAttempts(addresses_); | 95 socket_->StartLoggingMultipleConnectAttempts(addresses_); |
87 | 96 |
88 // We will try to connect to each address in addresses_. Start with the | 97 // We will try to connect to each address in addresses_. Start with the |
89 // first one in the list. | 98 // first one in the list. |
90 next_connect_state_ = CONNECT_STATE_CONNECT; | 99 next_connect_state_ = CONNECT_STATE_CONNECT; |
91 current_address_index_ = 0; | 100 current_address_index_ = 0; |
92 | 101 |
93 int rv = DoConnectLoop(OK); | 102 int rv = DoConnectLoop(OK); |
94 if (rv == ERR_IO_PENDING) { | 103 if (rv == ERR_IO_PENDING) { |
95 connect_callback_ = callback; | 104 connect_callback_ = callback; |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 } | 202 } |
194 | 203 |
195 // Otherwise there is nothing to fall back to, so give up. | 204 // Otherwise there is nothing to fall back to, so give up. |
196 return result; | 205 return result; |
197 } | 206 } |
198 | 207 |
199 void TCPClientSocket::Disconnect() { | 208 void TCPClientSocket::Disconnect() { |
200 DoDisconnect(); | 209 DoDisconnect(); |
201 current_address_index_ = -1; | 210 current_address_index_ = -1; |
202 bind_address_.reset(); | 211 bind_address_.reset(); |
| 212 |
| 213 // Cancel any pending callbacks. Not done in Disconnect() because that's |
| 214 // called on connection failure, when the connect callback will need to be |
| 215 // invoked. |
| 216 was_disconnected_on_suspend_ = false; |
| 217 connect_callback_.Reset(); |
| 218 read_callback_.Reset(); |
| 219 write_callback_.Reset(); |
203 } | 220 } |
204 | 221 |
205 void TCPClientSocket::DoDisconnect() { | 222 void TCPClientSocket::DoDisconnect() { |
206 total_received_bytes_ = 0; | 223 total_received_bytes_ = 0; |
207 EmitTCPMetricsHistogramsOnDisconnect(); | 224 EmitTCPMetricsHistogramsOnDisconnect(); |
208 // If connecting or already connected, record that the socket has been | 225 // If connecting or already connected, record that the socket has been |
209 // disconnected. | 226 // disconnected. |
210 previously_disconnected_ = socket_->IsValid() && current_address_index_ >= 0; | 227 previously_disconnected_ = socket_->IsValid() && current_address_index_ >= 0; |
211 socket_->Close(); | 228 socket_->Close(); |
| 229 |
| 230 // Invalidate weak pointers, so if in the middle of a callback in OnSuspend, |
| 231 // and something destroys this, no other callback is invoked. |
| 232 weak_ptr_factory_.InvalidateWeakPtrs(); |
212 } | 233 } |
213 | 234 |
214 bool TCPClientSocket::IsConnected() const { | 235 bool TCPClientSocket::IsConnected() const { |
215 return socket_->IsConnected(); | 236 return socket_->IsConnected(); |
216 } | 237 } |
217 | 238 |
218 bool TCPClientSocket::IsConnectedAndIdle() const { | 239 bool TCPClientSocket::IsConnectedAndIdle() const { |
219 return socket_->IsConnectedAndIdle(); | 240 return socket_->IsConnectedAndIdle(); |
220 } | 241 } |
221 | 242 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
262 } | 283 } |
263 | 284 |
264 NextProto TCPClientSocket::GetNegotiatedProtocol() const { | 285 NextProto TCPClientSocket::GetNegotiatedProtocol() const { |
265 return kProtoUnknown; | 286 return kProtoUnknown; |
266 } | 287 } |
267 | 288 |
268 bool TCPClientSocket::GetSSLInfo(SSLInfo* ssl_info) { | 289 bool TCPClientSocket::GetSSLInfo(SSLInfo* ssl_info) { |
269 return false; | 290 return false; |
270 } | 291 } |
271 | 292 |
| 293 void TCPClientSocket::SetFailOnSuspend(bool disconnect_on_suspend) { |
| 294 // Do nothing if building under NaCl. |
| 295 #if !defined(OS_NACL) |
| 296 // Do nothing if state is unchanged. |
| 297 if (disconnect_on_suspend_ == disconnect_on_suspend) |
| 298 return; |
| 299 |
| 300 // Otherwise, start/stop observing if there's a PowerMonitor configured, as |
| 301 // needed. |
| 302 base::PowerMonitor* power_monitor = base::PowerMonitor::Get(); |
| 303 if (!power_monitor) |
| 304 return; |
| 305 disconnect_on_suspend_ = disconnect_on_suspend; |
| 306 if (disconnect_on_suspend_) { |
| 307 power_monitor->AddObserver(this); |
| 308 } else { |
| 309 power_monitor->RemoveObserver(this); |
| 310 } |
| 311 #endif // !defined(OS_NACL) |
| 312 } |
| 313 |
272 int TCPClientSocket::Read(IOBuffer* buf, | 314 int TCPClientSocket::Read(IOBuffer* buf, |
273 int buf_len, | 315 int buf_len, |
274 const CompletionCallback& callback) { | 316 const CompletionCallback& callback) { |
275 DCHECK(!callback.is_null()); | 317 DCHECK(!callback.is_null()); |
| 318 DCHECK(read_callback_.is_null()); |
276 | 319 |
277 // |socket_| is owned by this class and the callback won't be run once | 320 // |socket_| is owned by this class and the callback won't be run once |
278 // |socket_| is gone. Therefore, it is safe to use base::Unretained() here. | 321 // |socket_| is gone. Therefore, it is safe to use base::Unretained() here. |
279 CompletionCallback read_callback = base::Bind( | 322 CompletionCallback read_callback = |
280 &TCPClientSocket::DidCompleteRead, base::Unretained(this), callback); | 323 base::Bind(&TCPClientSocket::DidCompleteRead, base::Unretained(this)); |
281 int result = socket_->Read(buf, buf_len, read_callback); | 324 int result = socket_->Read(buf, buf_len, read_callback); |
282 if (result > 0) { | 325 if (result == ERR_IO_PENDING) { |
| 326 read_callback_ = callback; |
| 327 } else if (result > 0) { |
283 use_history_.set_was_used_to_convey_data(); | 328 use_history_.set_was_used_to_convey_data(); |
284 total_received_bytes_ += result; | 329 total_received_bytes_ += result; |
285 } | 330 } |
286 | 331 |
287 return result; | 332 return result; |
288 } | 333 } |
289 | 334 |
290 int TCPClientSocket::Write(IOBuffer* buf, | 335 int TCPClientSocket::Write(IOBuffer* buf, |
291 int buf_len, | 336 int buf_len, |
292 const CompletionCallback& callback) { | 337 const CompletionCallback& callback) { |
293 DCHECK(!callback.is_null()); | 338 DCHECK(!callback.is_null()); |
| 339 DCHECK(write_callback_.is_null()); |
294 | 340 |
295 // |socket_| is owned by this class and the callback won't be run once | 341 // |socket_| is owned by this class and the callback won't be run once |
296 // |socket_| is gone. Therefore, it is safe to use base::Unretained() here. | 342 // |socket_| is gone. Therefore, it is safe to use base::Unretained() here. |
297 CompletionCallback write_callback = base::Bind( | 343 CompletionCallback write_callback = |
298 &TCPClientSocket::DidCompleteWrite, base::Unretained(this), callback); | 344 base::Bind(&TCPClientSocket::DidCompleteWrite, base::Unretained(this)); |
299 int result = socket_->Write(buf, buf_len, write_callback); | 345 int result = socket_->Write(buf, buf_len, write_callback); |
300 if (result > 0) | 346 if (result == ERR_IO_PENDING) { |
| 347 write_callback_ = callback; |
| 348 } else if (result > 0) { |
301 use_history_.set_was_used_to_convey_data(); | 349 use_history_.set_was_used_to_convey_data(); |
| 350 } |
302 | 351 |
303 return result; | 352 return result; |
304 } | 353 } |
305 | 354 |
306 int TCPClientSocket::SetReceiveBufferSize(int32_t size) { | 355 int TCPClientSocket::SetReceiveBufferSize(int32_t size) { |
307 return socket_->SetReceiveBufferSize(size); | 356 return socket_->SetReceiveBufferSize(size); |
308 } | 357 } |
309 | 358 |
310 int TCPClientSocket::SetSendBufferSize(int32_t size) { | 359 int TCPClientSocket::SetSendBufferSize(int32_t size) { |
311 return socket_->SetSendBufferSize(size); | 360 return socket_->SetSendBufferSize(size); |
312 } | 361 } |
313 | 362 |
314 bool TCPClientSocket::SetKeepAlive(bool enable, int delay) { | 363 bool TCPClientSocket::SetKeepAlive(bool enable, int delay) { |
315 return socket_->SetKeepAlive(enable, delay); | 364 return socket_->SetKeepAlive(enable, delay); |
316 } | 365 } |
317 | 366 |
318 bool TCPClientSocket::SetNoDelay(bool no_delay) { | 367 bool TCPClientSocket::SetNoDelay(bool no_delay) { |
319 return socket_->SetNoDelay(no_delay); | 368 return socket_->SetNoDelay(no_delay); |
320 } | 369 } |
321 | 370 |
322 void TCPClientSocket::GetConnectionAttempts(ConnectionAttempts* out) const { | 371 void TCPClientSocket::GetConnectionAttempts(ConnectionAttempts* out) const { |
323 *out = connection_attempts_; | 372 *out = connection_attempts_; |
324 } | 373 } |
325 | 374 |
326 void TCPClientSocket::ClearConnectionAttempts() { | 375 void TCPClientSocket::ClearConnectionAttempts() { |
327 connection_attempts_.clear(); | 376 connection_attempts_.clear(); |
328 } | 377 } |
329 | 378 |
330 void TCPClientSocket::AddConnectionAttempts( | 379 void TCPClientSocket::AddConnectionAttempts( |
331 const ConnectionAttempts& attempts) { | 380 const ConnectionAttempts& attempts) { |
332 connection_attempts_.insert(connection_attempts_.begin(), attempts.begin(), | 381 connection_attempts_.insert(connection_attempts_.begin(), attempts.begin(), |
333 attempts.end()); | 382 attempts.end()); |
334 } | 383 } |
335 | 384 |
336 int64_t TCPClientSocket::GetTotalReceivedBytes() const { | 385 int64_t TCPClientSocket::GetTotalReceivedBytes() const { |
337 return total_received_bytes_; | 386 return total_received_bytes_; |
338 } | 387 } |
339 | 388 |
| 389 void TCPClientSocket::OnSuspend() { |
| 390 // If the socket is connected, or connecting, act as if current and future |
| 391 // operations on the socket fail with ERR_NETWORK_IO_SUSPENDED, until the |
| 392 // socket is reconnected. |
| 393 // TODO(mmenke): This doesn't cover sockets created after OnSuspend runs, |
| 394 // just before suspend mode starts. Would it make more sense to do this on |
| 395 // resume? |
| 396 |
| 397 if (next_connect_state_ != CONNECT_STATE_NONE) { |
| 398 DidCompleteConnect(ERR_NETWORK_IO_SUSPENDED); |
| 399 return; |
| 400 } |
| 401 |
| 402 // Nothing to do. |
| 403 if (!IsConnected()) |
| 404 return; |
| 405 |
| 406 Disconnect(); |
| 407 |
| 408 was_disconnected_on_suspend_ = true; |
| 409 |
| 410 // Grab a weap pointer just in case calling read callback results in |this| |
| 411 // being destroyed, or disconnected. In either case, should not run the write |
| 412 // callback. |
| 413 base::WeakPtr<TCPClientSocket> weak_this = weak_ptr_factory_.GetWeakPtr(); |
| 414 |
| 415 if (read_callback_) |
| 416 DidCompleteRead(ERR_NETWORK_IO_SUSPENDED); |
| 417 if (weak_this && write_callback_) |
| 418 DidCompleteWrite(ERR_NETWORK_IO_SUSPENDED); |
| 419 } |
| 420 |
340 void TCPClientSocket::DidCompleteConnect(int result) { | 421 void TCPClientSocket::DidCompleteConnect(int result) { |
341 DCHECK_EQ(next_connect_state_, CONNECT_STATE_CONNECT_COMPLETE); | 422 DCHECK_EQ(next_connect_state_, CONNECT_STATE_CONNECT_COMPLETE); |
342 DCHECK_NE(result, ERR_IO_PENDING); | 423 DCHECK_NE(result, ERR_IO_PENDING); |
343 DCHECK(!connect_callback_.is_null()); | 424 DCHECK(!connect_callback_.is_null()); |
344 | 425 |
345 result = DoConnectLoop(result); | 426 result = DoConnectLoop(result); |
346 if (result != ERR_IO_PENDING) { | 427 if (result != ERR_IO_PENDING) { |
347 socket_->EndLoggingMultipleConnectAttempts(result); | 428 socket_->EndLoggingMultipleConnectAttempts(result); |
348 base::ResetAndReturn(&connect_callback_).Run(result); | 429 base::ResetAndReturn(&connect_callback_).Run(result); |
349 } | 430 } |
350 } | 431 } |
351 | 432 |
352 void TCPClientSocket::DidCompleteRead(const CompletionCallback& callback, | 433 void TCPClientSocket::DidCompleteRead(int result) { |
353 int result) { | 434 DCHECK(!read_callback_.is_null()); |
354 if (result > 0) | 435 if (result > 0) |
355 total_received_bytes_ += result; | 436 total_received_bytes_ += result; |
356 | 437 |
357 DidCompleteReadWrite(callback, result); | 438 DidCompleteReadWrite(base::ResetAndReturn(&read_callback_), result); |
358 } | 439 } |
359 | 440 |
360 void TCPClientSocket::DidCompleteWrite(const CompletionCallback& callback, | 441 void TCPClientSocket::DidCompleteWrite(int result) { |
361 int result) { | 442 DCHECK(!write_callback_.is_null()); |
362 DidCompleteReadWrite(callback, result); | 443 DidCompleteReadWrite(base::ResetAndReturn(&write_callback_), result); |
363 } | 444 } |
364 | 445 |
365 void TCPClientSocket::DidCompleteReadWrite(const CompletionCallback& callback, | 446 void TCPClientSocket::DidCompleteReadWrite(const CompletionCallback& callback, |
366 int result) { | 447 int result) { |
367 if (result > 0) | 448 if (result > 0) |
368 use_history_.set_was_used_to_convey_data(); | 449 use_history_.set_was_used_to_convey_data(); |
369 | 450 |
370 // TODO(pkasting): Remove ScopedTracker below once crbug.com/462780 is fixed. | 451 // TODO(pkasting): Remove ScopedTracker below once crbug.com/462780 is fixed. |
371 tracked_objects::ScopedTracker tracking_profile( | 452 tracked_objects::ScopedTracker tracking_profile( |
372 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 453 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
(...skipping 16 matching lines...) Expand all Loading... |
389 void TCPClientSocket::EmitTCPMetricsHistogramsOnDisconnect() { | 470 void TCPClientSocket::EmitTCPMetricsHistogramsOnDisconnect() { |
390 base::TimeDelta rtt; | 471 base::TimeDelta rtt; |
391 if (socket_->GetEstimatedRoundTripTime(&rtt)) { | 472 if (socket_->GetEstimatedRoundTripTime(&rtt)) { |
392 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TcpRtt.AtDisconnect", rtt, | 473 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TcpRtt.AtDisconnect", rtt, |
393 base::TimeDelta::FromMilliseconds(1), | 474 base::TimeDelta::FromMilliseconds(1), |
394 base::TimeDelta::FromMinutes(10), 100); | 475 base::TimeDelta::FromMinutes(10), 100); |
395 } | 476 } |
396 } | 477 } |
397 | 478 |
398 } // namespace net | 479 } // namespace net |
OLD | NEW |