| 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 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 } | 222 } |
| 214 | 223 |
| 215 // Otherwise there is nothing to fall back to, so give up. | 224 // Otherwise there is nothing to fall back to, so give up. |
| 216 return result; | 225 return result; |
| 217 } | 226 } |
| 218 | 227 |
| 219 void TCPClientSocket::Disconnect() { | 228 void TCPClientSocket::Disconnect() { |
| 220 DoDisconnect(); | 229 DoDisconnect(); |
| 221 current_address_index_ = -1; | 230 current_address_index_ = -1; |
| 222 bind_address_.reset(); | 231 bind_address_.reset(); |
| 232 |
| 233 // Cancel any pending callbacks. Not done in Disconnect() because that's |
| 234 // called on connection failure, when the connect callback will need to be |
| 235 // invoked. |
| 236 was_disconnected_on_suspend_ = false; |
| 237 connect_callback_.Reset(); |
| 238 read_callback_.Reset(); |
| 239 write_callback_.Reset(); |
| 223 } | 240 } |
| 224 | 241 |
| 225 void TCPClientSocket::DoDisconnect() { | 242 void TCPClientSocket::DoDisconnect() { |
| 226 total_received_bytes_ = 0; | 243 total_received_bytes_ = 0; |
| 227 EmitTCPMetricsHistogramsOnDisconnect(); | 244 EmitTCPMetricsHistogramsOnDisconnect(); |
| 228 // If connecting or already connected, record that the socket has been | 245 // If connecting or already connected, record that the socket has been |
| 229 // disconnected. | 246 // disconnected. |
| 230 previously_disconnected_ = socket_->IsValid() && current_address_index_ >= 0; | 247 previously_disconnected_ = socket_->IsValid() && current_address_index_ >= 0; |
| 231 socket_->Close(); | 248 socket_->Close(); |
| 249 |
| 250 // Invalidate weak pointers, so if in the middle of a callback in OnSuspend, |
| 251 // and something destroys this, no other callback is invoked. |
| 252 weak_ptr_factory_.InvalidateWeakPtrs(); |
| 232 } | 253 } |
| 233 | 254 |
| 234 bool TCPClientSocket::IsConnected() const { | 255 bool TCPClientSocket::IsConnected() const { |
| 235 return socket_->IsConnected(); | 256 return socket_->IsConnected(); |
| 236 } | 257 } |
| 237 | 258 |
| 238 bool TCPClientSocket::IsConnectedAndIdle() const { | 259 bool TCPClientSocket::IsConnectedAndIdle() const { |
| 239 return socket_->IsConnectedAndIdle(); | 260 return socket_->IsConnectedAndIdle(); |
| 240 } | 261 } |
| 241 | 262 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 } | 303 } |
| 283 | 304 |
| 284 NextProto TCPClientSocket::GetNegotiatedProtocol() const { | 305 NextProto TCPClientSocket::GetNegotiatedProtocol() const { |
| 285 return kProtoUnknown; | 306 return kProtoUnknown; |
| 286 } | 307 } |
| 287 | 308 |
| 288 bool TCPClientSocket::GetSSLInfo(SSLInfo* ssl_info) { | 309 bool TCPClientSocket::GetSSLInfo(SSLInfo* ssl_info) { |
| 289 return false; | 310 return false; |
| 290 } | 311 } |
| 291 | 312 |
| 313 void TCPClientSocket::SetFailOnSuspend(bool disconnect_on_suspend) { |
| 314 // Do nothing if building under NaCl. |
| 315 #if !defined(OS_NACL) |
| 316 // Do nothing if state is unchanged. |
| 317 if (disconnect_on_suspend_ == disconnect_on_suspend) |
| 318 return; |
| 319 |
| 320 // Otherwise, start/stop observing if there's a PowerMonitor configured, as |
| 321 // needed. |
| 322 base::PowerMonitor* power_monitor = base::PowerMonitor::Get(); |
| 323 if (!power_monitor) |
| 324 return; |
| 325 disconnect_on_suspend_ = disconnect_on_suspend; |
| 326 if (disconnect_on_suspend_) { |
| 327 power_monitor->AddObserver(this); |
| 328 } else { |
| 329 power_monitor->RemoveObserver(this); |
| 330 } |
| 331 #endif // !defined(OS_NACL) |
| 332 } |
| 333 |
| 292 int TCPClientSocket::Read(IOBuffer* buf, | 334 int TCPClientSocket::Read(IOBuffer* buf, |
| 293 int buf_len, | 335 int buf_len, |
| 294 const CompletionCallback& callback) { | 336 const CompletionCallback& callback) { |
| 295 return ReadCommon(buf, buf_len, callback, /*read_if_ready=*/false); | 337 return ReadCommon(buf, buf_len, callback, /*read_if_ready=*/false); |
| 296 } | 338 } |
| 297 | 339 |
| 298 int TCPClientSocket::ReadIfReady(IOBuffer* buf, | 340 int TCPClientSocket::ReadIfReady(IOBuffer* buf, |
| 299 int buf_len, | 341 int buf_len, |
| 300 const CompletionCallback& callback) { | 342 const CompletionCallback& callback) { |
| 301 return ReadCommon(buf, buf_len, callback, /*read_if_ready=*/true); | 343 return ReadCommon(buf, buf_len, callback, /*read_if_ready=*/true); |
| 302 } | 344 } |
| 303 | 345 |
| 304 int TCPClientSocket::Write(IOBuffer* buf, | 346 int TCPClientSocket::Write(IOBuffer* buf, |
| 305 int buf_len, | 347 int buf_len, |
| 306 const CompletionCallback& callback) { | 348 const CompletionCallback& callback) { |
| 307 DCHECK(!callback.is_null()); | 349 DCHECK(!callback.is_null()); |
| 350 DCHECK(write_callback_.is_null()); |
| 308 | 351 |
| 309 // |socket_| is owned by this class and the callback won't be run once | 352 // |socket_| is owned by this class and the callback won't be run once |
| 310 // |socket_| is gone. Therefore, it is safe to use base::Unretained() here. | 353 // |socket_| is gone. Therefore, it is safe to use base::Unretained() here. |
| 311 CompletionCallback write_callback = base::Bind( | 354 CompletionCallback write_callback = |
| 312 &TCPClientSocket::DidCompleteWrite, base::Unretained(this), callback); | 355 base::Bind(&TCPClientSocket::DidCompleteWrite, base::Unretained(this)); |
| 313 int result = socket_->Write(buf, buf_len, write_callback); | 356 int result = socket_->Write(buf, buf_len, write_callback); |
| 314 if (result > 0) | 357 if (result == ERR_IO_PENDING) { |
| 358 write_callback_ = callback; |
| 359 } else if (result > 0) { |
| 315 use_history_.set_was_used_to_convey_data(); | 360 use_history_.set_was_used_to_convey_data(); |
| 361 } |
| 316 | 362 |
| 317 return result; | 363 return result; |
| 318 } | 364 } |
| 319 | 365 |
| 320 int TCPClientSocket::SetReceiveBufferSize(int32_t size) { | 366 int TCPClientSocket::SetReceiveBufferSize(int32_t size) { |
| 321 return socket_->SetReceiveBufferSize(size); | 367 return socket_->SetReceiveBufferSize(size); |
| 322 } | 368 } |
| 323 | 369 |
| 324 int TCPClientSocket::SetSendBufferSize(int32_t size) { | 370 int TCPClientSocket::SetSendBufferSize(int32_t size) { |
| 325 return socket_->SetSendBufferSize(size); | 371 return socket_->SetSendBufferSize(size); |
| 326 } | 372 } |
| 327 | 373 |
| 328 bool TCPClientSocket::SetKeepAlive(bool enable, int delay) { | 374 bool TCPClientSocket::SetKeepAlive(bool enable, int delay) { |
| 329 return socket_->SetKeepAlive(enable, delay); | 375 return socket_->SetKeepAlive(enable, delay); |
| 330 } | 376 } |
| 331 | 377 |
| 332 bool TCPClientSocket::SetNoDelay(bool no_delay) { | 378 bool TCPClientSocket::SetNoDelay(bool no_delay) { |
| 333 return socket_->SetNoDelay(no_delay); | 379 return socket_->SetNoDelay(no_delay); |
| 334 } | 380 } |
| 335 | 381 |
| 336 void TCPClientSocket::GetConnectionAttempts(ConnectionAttempts* out) const { | 382 void TCPClientSocket::GetConnectionAttempts(ConnectionAttempts* out) const { |
| 337 *out = connection_attempts_; | 383 *out = connection_attempts_; |
| 338 } | 384 } |
| 339 | 385 |
| 340 void TCPClientSocket::ClearConnectionAttempts() { | 386 void TCPClientSocket::ClearConnectionAttempts() { |
| 341 connection_attempts_.clear(); | 387 connection_attempts_.clear(); |
| 342 } | 388 } |
| 343 | 389 |
| 344 void TCPClientSocket::AddConnectionAttempts( | 390 void TCPClientSocket::AddConnectionAttempts( |
| 345 const ConnectionAttempts& attempts) { | 391 const ConnectionAttempts& attempts) { |
| 346 connection_attempts_.insert(connection_attempts_.begin(), attempts.begin(), | 392 connection_attempts_.insert(connection_attempts_.begin(), attempts.begin(), |
| 347 attempts.end()); | 393 attempts.end()); |
| 348 } | 394 } |
| 349 | 395 |
| 350 int64_t TCPClientSocket::GetTotalReceivedBytes() const { | 396 int64_t TCPClientSocket::GetTotalReceivedBytes() const { |
| 351 return total_received_bytes_; | 397 return total_received_bytes_; |
| 352 } | 398 } |
| 353 | 399 |
| 400 void TCPClientSocket::OnSuspend() { |
| 401 // If the socket is connected, or connecting, act as if current and future |
| 402 // operations on the socket fail with ERR_NETWORK_IO_SUSPENDED, until the |
| 403 // socket is reconnected. |
| 404 // TODO(mmenke): This doesn't cover sockets created after OnSuspend runs, |
| 405 // just before suspend mode starts. Would it make more sense to do this on |
| 406 // resume? |
| 407 |
| 408 if (next_connect_state_ != CONNECT_STATE_NONE) { |
| 409 DidCompleteConnect(ERR_NETWORK_IO_SUSPENDED); |
| 410 return; |
| 411 } |
| 412 |
| 413 // Nothing to do. |
| 414 if (!IsConnected()) |
| 415 return; |
| 416 |
| 417 Disconnect(); |
| 418 |
| 419 was_disconnected_on_suspend_ = true; |
| 420 |
| 421 // Grab a weap pointer just in case calling read callback results in |this| |
| 422 // being destroyed, or disconnected. In either case, should not run the write |
| 423 // callback. |
| 424 base::WeakPtr<TCPClientSocket> weak_this = weak_ptr_factory_.GetWeakPtr(); |
| 425 |
| 426 if (read_callback_) |
| 427 DidCompleteRead(ERR_NETWORK_IO_SUSPENDED); |
| 428 if (weak_this && write_callback_) |
| 429 DidCompleteWrite(ERR_NETWORK_IO_SUSPENDED); |
| 430 } |
| 431 |
| 354 void TCPClientSocket::DidCompleteConnect(int result) { | 432 void TCPClientSocket::DidCompleteConnect(int result) { |
| 355 DCHECK_EQ(next_connect_state_, CONNECT_STATE_CONNECT_COMPLETE); | 433 DCHECK_EQ(next_connect_state_, CONNECT_STATE_CONNECT_COMPLETE); |
| 356 DCHECK_NE(result, ERR_IO_PENDING); | 434 DCHECK_NE(result, ERR_IO_PENDING); |
| 357 DCHECK(!connect_callback_.is_null()); | 435 DCHECK(!connect_callback_.is_null()); |
| 358 | 436 |
| 359 result = DoConnectLoop(result); | 437 result = DoConnectLoop(result); |
| 360 if (result != ERR_IO_PENDING) { | 438 if (result != ERR_IO_PENDING) { |
| 361 socket_->EndLoggingMultipleConnectAttempts(result); | 439 socket_->EndLoggingMultipleConnectAttempts(result); |
| 362 base::ResetAndReturn(&connect_callback_).Run(result); | 440 base::ResetAndReturn(&connect_callback_).Run(result); |
| 363 } | 441 } |
| 364 } | 442 } |
| 365 | 443 |
| 366 void TCPClientSocket::DidCompleteRead(const CompletionCallback& callback, | 444 void TCPClientSocket::DidCompleteRead(int result) { |
| 367 int result) { | 445 DCHECK(!read_callback_.is_null()); |
| 368 if (result > 0) | 446 if (result > 0) |
| 369 total_received_bytes_ += result; | 447 total_received_bytes_ += result; |
| 370 | 448 |
| 371 DidCompleteReadWrite(callback, result); | 449 DidCompleteReadWrite(base::ResetAndReturn(&read_callback_), result); |
| 372 } | 450 } |
| 373 | 451 |
| 374 void TCPClientSocket::DidCompleteWrite(const CompletionCallback& callback, | 452 void TCPClientSocket::DidCompleteWrite(int result) { |
| 375 int result) { | 453 DCHECK(!write_callback_.is_null()); |
| 376 DidCompleteReadWrite(callback, result); | 454 DidCompleteReadWrite(base::ResetAndReturn(&write_callback_), result); |
| 377 } | 455 } |
| 378 | 456 |
| 379 void TCPClientSocket::DidCompleteReadWrite(const CompletionCallback& callback, | 457 void TCPClientSocket::DidCompleteReadWrite(const CompletionCallback& callback, |
| 380 int result) { | 458 int result) { |
| 381 if (result > 0) | 459 if (result > 0) |
| 382 use_history_.set_was_used_to_convey_data(); | 460 use_history_.set_was_used_to_convey_data(); |
| 383 | 461 |
| 384 // TODO(pkasting): Remove ScopedTracker below once crbug.com/462780 is fixed. | 462 // TODO(pkasting): Remove ScopedTracker below once crbug.com/462780 is fixed. |
| 385 tracked_objects::ScopedTracker tracking_profile( | 463 tracked_objects::ScopedTracker tracking_profile( |
| 386 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 464 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| (...skipping 16 matching lines...) Expand all Loading... |
| 403 void TCPClientSocket::EmitTCPMetricsHistogramsOnDisconnect() { | 481 void TCPClientSocket::EmitTCPMetricsHistogramsOnDisconnect() { |
| 404 base::TimeDelta rtt; | 482 base::TimeDelta rtt; |
| 405 if (socket_->GetEstimatedRoundTripTime(&rtt)) { | 483 if (socket_->GetEstimatedRoundTripTime(&rtt)) { |
| 406 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TcpRtt.AtDisconnect", rtt, | 484 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TcpRtt.AtDisconnect", rtt, |
| 407 base::TimeDelta::FromMilliseconds(1), | 485 base::TimeDelta::FromMilliseconds(1), |
| 408 base::TimeDelta::FromMinutes(10), 100); | 486 base::TimeDelta::FromMinutes(10), 100); |
| 409 } | 487 } |
| 410 } | 488 } |
| 411 | 489 |
| 412 } // namespace net | 490 } // namespace net |
| OLD | NEW |