Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(219)

Side by Side Diff: net/socket/tcp_client_socket.cc

Issue 2447083003: Move fail on suspend logic from URLRequestJob to TcpClientSocket.
Patch Set: . Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/socket/tcp_client_socket.h ('k') | net/socket/transport_client_socket_pool.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « net/socket/tcp_client_socket.h ('k') | net/socket/transport_client_socket_pool.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698