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 |