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

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

Powered by Google App Engine
This is Rietveld 408576698