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

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

Issue 2447083003: Move fail on suspend logic from URLRequestJob to TcpClientSocket.
Patch Set: Fix connect error case Created 4 years, 1 month 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
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 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698