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

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

Issue 451383002: Plumbing for TCP FastOpen for SSL sockets. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comments addressed. Created 6 years, 3 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
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 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_socket.h" 5 #include "net/socket/tcp_socket.h"
6 6
7 #include <errno.h> 7 #include <errno.h>
8 #include <netinet/tcp.h> 8 #include <netinet/tcp.h>
9 #include <sys/socket.h> 9 #include <sys/socket.h>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/metrics/histogram.h" 13 #include "base/metrics/histogram.h"
14 #include "base/metrics/stats_counters.h" 14 #include "base/metrics/stats_counters.h"
15 #include "base/posix/eintr_wrapper.h" 15 #include "base/posix/eintr_wrapper.h"
16 #include "base/task_runner_util.h"
17 #include "base/threading/worker_pool.h"
16 #include "net/base/address_list.h" 18 #include "net/base/address_list.h"
17 #include "net/base/connection_type_histograms.h" 19 #include "net/base/connection_type_histograms.h"
18 #include "net/base/io_buffer.h" 20 #include "net/base/io_buffer.h"
19 #include "net/base/ip_endpoint.h" 21 #include "net/base/ip_endpoint.h"
20 #include "net/base/net_errors.h" 22 #include "net/base/net_errors.h"
21 #include "net/base/net_util.h" 23 #include "net/base/net_util.h"
22 #include "net/base/network_change_notifier.h" 24 #include "net/base/network_change_notifier.h"
23 #include "net/socket/socket_libevent.h" 25 #include "net/socket/socket_libevent.h"
24 #include "net/socket/socket_net_log_params.h" 26 #include "net/socket/socket_net_log_params.h"
25 27
26 // If we don't have a definition for TCPI_OPT_SYN_DATA, create one. 28 // If we don't have a definition for TCPI_OPT_SYN_DATA, create one.
27 #ifndef TCPI_OPT_SYN_DATA 29 #ifndef TCPI_OPT_SYN_DATA
28 #define TCPI_OPT_SYN_DATA 32 30 #define TCPI_OPT_SYN_DATA 32
29 #endif 31 #endif
30 32
33 // True if OS supports TCP FastOpen.
34 bool g_tcp_fastopen_supported = false;
35 // True if TCP FastOpen is user-enabled for all connections.
36 // TODO(jri): Change global variable to param in HttpNetworkSession::Params.
37 bool g_tcp_fastopen_user_enabled = false;
38
31 namespace net { 39 namespace net {
32 40
33 namespace { 41 namespace {
34 42
35 // SetTCPNoDelay turns on/off buffering in the kernel. By default, TCP sockets 43 // SetTCPNoDelay turns on/off buffering in the kernel. By default, TCP sockets
36 // will wait up to 200ms for more data to complete a packet before transmitting. 44 // will wait up to 200ms for more data to complete a packet before transmitting.
37 // After calling this function, the kernel will not wait. See TCP_NODELAY in 45 // After calling this function, the kernel will not wait. See TCP_NODELAY in
38 // `man 7 tcp`. 46 // `man 7 tcp`.
39 bool SetTCPNoDelay(int fd, bool no_delay) { 47 bool SetTCPNoDelay(int fd, bool no_delay) {
40 int on = no_delay ? 1 : 0; 48 int on = no_delay ? 1 : 0;
(...skipping 21 matching lines...) Expand all
62 } 70 }
63 // Set seconds between TCP keep alives. 71 // Set seconds between TCP keep alives.
64 if (setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &delay, sizeof(delay))) { 72 if (setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &delay, sizeof(delay))) {
65 PLOG(ERROR) << "Failed to set TCP_KEEPINTVL on fd: " << fd; 73 PLOG(ERROR) << "Failed to set TCP_KEEPINTVL on fd: " << fd;
66 return false; 74 return false;
67 } 75 }
68 #endif 76 #endif
69 return true; 77 return true;
70 } 78 }
71 79
80 #if defined(OS_LINUX) || defined(OS_ANDROID)
81 // Checks if the kernel supports TCP FastOpen.
82 bool SystemSupportsTCPFastOpen() {
83 const base::FilePath::CharType kTCPFastOpenProcFilePath[] =
84 "/proc/sys/net/ipv4/tcp_fastopen";
85 std::string system_supports_tcp_fastopen;
86 if (!base::ReadFileToString(base::FilePath(kTCPFastOpenProcFilePath),
87 &system_supports_tcp_fastopen)) {
88 return false;
89 }
90 // The read from /proc should return '1' if TCP FastOpen is enabled in the OS.
91 if (system_supports_tcp_fastopen.empty() ||
92 (system_supports_tcp_fastopen[0] != '1')) {
93 return false;
94 }
95 return true;
96 }
97
98 void RegisterTCPFastOpenIntentAndSupport(bool user_enabled,
99 bool system_supported) {
100 g_tcp_fastopen_supported = system_supported;
101 g_tcp_fastopen_user_enabled = user_enabled;
102 }
103 #endif
104
105 // Check if TCP FastOpen option is supported by the OS.
106 bool IsTCPFastOpenSupported() {
107 return g_tcp_fastopen_supported;
108 }
109
72 } // namespace 110 } // namespace
73 111
74 //----------------------------------------------------------------------------- 112 //-----------------------------------------------------------------------------
75 113
114 // This is asynchronous because it needs to do file IO, and it isn't allowed to
115 // do that on the IO thread.
116 void CheckSupportAndMaybeEnableTCPFastOpen(bool user_enabled) {
117 #if defined(OS_LINUX) || defined(OS_ANDROID)
118 base::PostTaskAndReplyWithResult(
119 base::WorkerPool::GetTaskRunner(/*task_is_slow=*/false),
120 FROM_HERE,
121 base::Bind(SystemSupportsTCPFastOpen),
122 base::Bind(RegisterTCPFastOpenIntentAndSupport, user_enabled));
123 #endif
124 }
125
76 TCPSocketLibevent::TCPSocketLibevent(NetLog* net_log, 126 TCPSocketLibevent::TCPSocketLibevent(NetLog* net_log,
77 const NetLog::Source& source) 127 const NetLog::Source& source)
78 : use_tcp_fastopen_(IsTCPFastOpenEnabled()), 128 : use_tcp_fastopen_(false),
79 tcp_fastopen_connected_(false), 129 tcp_fastopen_connected_(false),
80 fast_open_status_(FAST_OPEN_STATUS_UNKNOWN), 130 fast_open_status_(FAST_OPEN_STATUS_UNKNOWN),
81 logging_multiple_connect_attempts_(false), 131 logging_multiple_connect_attempts_(false),
82 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) { 132 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
83 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, 133 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
84 source.ToEventParametersCallback()); 134 source.ToEventParametersCallback());
85 } 135 }
86 136
87 TCPSocketLibevent::~TCPSocketLibevent() { 137 TCPSocketLibevent::~TCPSocketLibevent() {
88 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE); 138 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 void TCPSocketLibevent::Close() { 412 void TCPSocketLibevent::Close() {
363 socket_.reset(); 413 socket_.reset();
364 tcp_fastopen_connected_ = false; 414 tcp_fastopen_connected_ = false;
365 fast_open_status_ = FAST_OPEN_STATUS_UNKNOWN; 415 fast_open_status_ = FAST_OPEN_STATUS_UNKNOWN;
366 } 416 }
367 417
368 bool TCPSocketLibevent::UsingTCPFastOpen() const { 418 bool TCPSocketLibevent::UsingTCPFastOpen() const {
369 return use_tcp_fastopen_; 419 return use_tcp_fastopen_;
370 } 420 }
371 421
422 void TCPSocketLibevent::EnableTCPFastOpen() {
423 if (IsTCPFastOpenSupported())
424 use_tcp_fastopen_ = true;
425 }
426
372 bool TCPSocketLibevent::IsValid() const { 427 bool TCPSocketLibevent::IsValid() const {
373 return socket_ != NULL && socket_->socket_fd() != kInvalidSocket; 428 return socket_ != NULL && socket_->socket_fd() != kInvalidSocket;
374 } 429 }
375 430
376 void TCPSocketLibevent::StartLoggingMultipleConnectAttempts( 431 void TCPSocketLibevent::StartLoggingMultipleConnectAttempts(
377 const AddressList& addresses) { 432 const AddressList& addresses) {
378 if (!logging_multiple_connect_attempts_) { 433 if (!logging_multiple_connect_attempts_) {
379 logging_multiple_connect_attempts_ = true; 434 logging_multiple_connect_attempts_ = true;
380 LogConnectBegin(addresses); 435 LogConnectBegin(addresses);
381 } else { 436 } else {
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
488 543
489 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT, 544 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT,
490 CreateNetLogSourceAddressCallback(storage.addr, 545 CreateNetLogSourceAddressCallback(storage.addr,
491 storage.addr_len)); 546 storage.addr_len));
492 } 547 }
493 548
494 void TCPSocketLibevent::ReadCompleted(const scoped_refptr<IOBuffer>& buf, 549 void TCPSocketLibevent::ReadCompleted(const scoped_refptr<IOBuffer>& buf,
495 const CompletionCallback& callback, 550 const CompletionCallback& callback,
496 int rv) { 551 int rv) {
497 DCHECK_NE(ERR_IO_PENDING, rv); 552 DCHECK_NE(ERR_IO_PENDING, rv);
498 // Records fast open status regardless of error in asynchronous case. 553 // Records TCP FastOpen status regardless of error in asynchronous case.
499 // TODO(rdsmith,jri): Change histogram name to indicate it could be called on 554 // TODO(rdsmith,jri): Change histogram name to indicate it could be called on
500 // error. 555 // error.
501 RecordFastOpenStatus(); 556 RecordFastOpenStatus();
502 callback.Run(HandleReadCompleted(buf.get(), rv)); 557 callback.Run(HandleReadCompleted(buf.get(), rv));
503 } 558 }
504 559
505 int TCPSocketLibevent::HandleReadCompleted(IOBuffer* buf, int rv) { 560 int TCPSocketLibevent::HandleReadCompleted(IOBuffer* buf, int rv) {
506 if (rv < 0) { 561 if (rv < 0) {
507 net_log_.AddEvent(NetLog::TYPE_SOCKET_READ_ERROR, 562 net_log_.AddEvent(NetLog::TYPE_SOCKET_READ_ERROR,
508 CreateNetLogSocketErrorCallback(rv, errno)); 563 CreateNetLogSocketErrorCallback(rv, errno));
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 } 645 }
591 646
592 void TCPSocketLibevent::RecordFastOpenStatus() { 647 void TCPSocketLibevent::RecordFastOpenStatus() {
593 if (use_tcp_fastopen_ && 648 if (use_tcp_fastopen_ &&
594 (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN || 649 (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN ||
595 fast_open_status_ == FAST_OPEN_SLOW_CONNECT_RETURN)) { 650 fast_open_status_ == FAST_OPEN_SLOW_CONNECT_RETURN)) {
596 DCHECK_NE(FAST_OPEN_STATUS_UNKNOWN, fast_open_status_); 651 DCHECK_NE(FAST_OPEN_STATUS_UNKNOWN, fast_open_status_);
597 bool getsockopt_success(false); 652 bool getsockopt_success(false);
598 bool server_acked_data(false); 653 bool server_acked_data(false);
599 #if defined(TCP_INFO) 654 #if defined(TCP_INFO)
600 // Probe to see the if the socket used TCP Fast Open. 655 // Probe to see the if the socket used TCP FastOpen.
601 tcp_info info; 656 tcp_info info;
602 socklen_t info_len = sizeof(tcp_info); 657 socklen_t info_len = sizeof(tcp_info);
603 getsockopt_success = 658 getsockopt_success =
604 getsockopt(socket_->socket_fd(), IPPROTO_TCP, TCP_INFO, 659 getsockopt(socket_->socket_fd(), IPPROTO_TCP, TCP_INFO,
605 &info, &info_len) == 0 && 660 &info, &info_len) == 0 &&
606 info_len == sizeof(tcp_info); 661 info_len == sizeof(tcp_info);
607 server_acked_data = getsockopt_success && 662 server_acked_data = getsockopt_success &&
608 (info.tcpi_options & TCPI_OPT_SYN_DATA); 663 (info.tcpi_options & TCPI_OPT_SYN_DATA);
609 #endif 664 #endif
610 if (getsockopt_success) { 665 if (getsockopt_success) {
611 if (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN) { 666 if (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN) {
612 fast_open_status_ = (server_acked_data ? FAST_OPEN_SYN_DATA_ACK : 667 fast_open_status_ = (server_acked_data ? FAST_OPEN_SYN_DATA_ACK :
613 FAST_OPEN_SYN_DATA_NACK); 668 FAST_OPEN_SYN_DATA_NACK);
614 } else { 669 } else {
615 fast_open_status_ = (server_acked_data ? FAST_OPEN_NO_SYN_DATA_ACK : 670 fast_open_status_ = (server_acked_data ? FAST_OPEN_NO_SYN_DATA_ACK :
616 FAST_OPEN_NO_SYN_DATA_NACK); 671 FAST_OPEN_NO_SYN_DATA_NACK);
617 } 672 }
618 } else { 673 } else {
619 fast_open_status_ = (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN ? 674 fast_open_status_ = (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN ?
620 FAST_OPEN_SYN_DATA_FAILED : 675 FAST_OPEN_SYN_DATA_FAILED :
621 FAST_OPEN_NO_SYN_DATA_FAILED); 676 FAST_OPEN_NO_SYN_DATA_FAILED);
622 } 677 }
623 } 678 }
624 } 679 }
625 680
626 } // namespace net 681 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698