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

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 constructor param in TransportSocketParams to enable TFO (and some cleanup) Created 6 years, 4 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_socket_libevent.h ('k') | net/socket/transport_client_socket_pool.h » ('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 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 OS supports TCP FastOpen and is turned on for all connections.
36 // TODO(jri): Change global variable to param in HttpNetworkSession::Params.
37 bool g_tcp_fastopen_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 static 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 CallbackForTCPFastOpenCheck(bool user_enabled,
99 bool system_supported) {
100 g_tcp_fastopen_supported = system_supported;
101 if (user_enabled) {
102 g_tcp_fastopen_enabled = system_supported;
103 }
104 }
105 #endif
106
107 // Check if TCP FastOpen option is supported by the OS.
108 bool IsTCPFastOpenSupported() {
109 return g_tcp_fastopen_supported;
110 }
111
112 // Check if TCP FastOpen option is enabled.
113 bool IsTCPFastOpenEnabled() {
114 return g_tcp_fastopen_enabled;
115 }
116
72 } // namespace 117 } // namespace
73 118
74 //----------------------------------------------------------------------------- 119 //-----------------------------------------------------------------------------
75 120
121 // This is asynchronous because it needs to do file IO, and it isn't allowed to
122 // do that on the IO thread.
123 void CheckSupportAndMaybeEnableTCPFastOpen(bool user_enabled) {
Randy Smith (Not in Mondays) 2014/08/19 18:25:43 This looks to be called on all platforms but not d
Jana 2014/08/22 03:35:19 Ah -- Great catch! Yes, it is not defined... will
124 #if defined(OS_LINUX) || defined(OS_ANDROID)
125 base::PostTaskAndReplyWithResult(
126 base::WorkerPool::GetTaskRunner(/*task_is_slow=*/false),
127 FROM_HERE,
128 base::Bind(SystemSupportsTCPFastOpen),
129 base::Bind(CallbackForTCPFastOpenCheck, user_enabled));
130 #endif
131 }
132
76 TCPSocketLibevent::TCPSocketLibevent(NetLog* net_log, 133 TCPSocketLibevent::TCPSocketLibevent(NetLog* net_log,
77 const NetLog::Source& source) 134 const NetLog::Source& source)
78 : use_tcp_fastopen_(IsTCPFastOpenEnabled()), 135 : use_tcp_fastopen_if_supported_(IsTCPFastOpenEnabled()),
79 tcp_fastopen_connected_(false), 136 tcp_fastopen_connected_(false),
80 fast_open_status_(FAST_OPEN_STATUS_UNKNOWN), 137 fast_open_status_(FAST_OPEN_STATUS_UNKNOWN),
81 logging_multiple_connect_attempts_(false), 138 logging_multiple_connect_attempts_(false),
82 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) { 139 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
83 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, 140 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
84 source.ToEventParametersCallback()); 141 source.ToEventParametersCallback());
85 } 142 }
86 143
87 TCPSocketLibevent::~TCPSocketLibevent() { 144 TCPSocketLibevent::~TCPSocketLibevent() {
88 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE); 145 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 if (!logging_multiple_connect_attempts_) 217 if (!logging_multiple_connect_attempts_)
161 LogConnectBegin(AddressList(address)); 218 LogConnectBegin(AddressList(address));
162 219
163 net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT, 220 net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT,
164 CreateNetLogIPEndPointCallback(&address)); 221 CreateNetLogIPEndPointCallback(&address));
165 222
166 SockaddrStorage storage; 223 SockaddrStorage storage;
167 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) 224 if (!address.ToSockAddr(storage.addr, &storage.addr_len))
168 return ERR_ADDRESS_INVALID; 225 return ERR_ADDRESS_INVALID;
169 226
170 if (use_tcp_fastopen_) { 227 if (use_tcp_fastopen_if_supported_) {
171 // With TCP FastOpen, we pretend that the socket is connected. 228 // With TCP FastOpen, we pretend that the socket is connected.
172 DCHECK(!tcp_fastopen_connected_); 229 DCHECK(!tcp_fastopen_connected_);
173 socket_->SetPeerAddress(storage); 230 socket_->SetPeerAddress(storage);
174 return OK; 231 return OK;
175 } 232 }
176 233
177 int rv = socket_->Connect(storage, 234 int rv = socket_->Connect(storage,
178 base::Bind(&TCPSocketLibevent::ConnectCompleted, 235 base::Bind(&TCPSocketLibevent::ConnectCompleted,
179 base::Unretained(this), callback)); 236 base::Unretained(this), callback));
180 if (rv != ERR_IO_PENDING) 237 if (rv != ERR_IO_PENDING)
181 rv = HandleConnectCompleted(rv); 238 rv = HandleConnectCompleted(rv);
182 return rv; 239 return rv;
183 } 240 }
184 241
185 bool TCPSocketLibevent::IsConnected() const { 242 bool TCPSocketLibevent::IsConnected() const {
186 if (!socket_) 243 if (!socket_)
187 return false; 244 return false;
188 245
189 if (use_tcp_fastopen_ && !tcp_fastopen_connected_ && 246 if (use_tcp_fastopen_if_supported_ && !tcp_fastopen_connected_ &&
190 socket_->HasPeerAddress()) { 247 socket_->HasPeerAddress()) {
191 // With TCP FastOpen, we pretend that the socket is connected. 248 // With TCP FastOpen, we pretend that the socket is connected.
192 // This allows GetPeerAddress() to return peer_address_. 249 // This allows GetPeerAddress() to return peer_address_.
193 return true; 250 return true;
194 } 251 }
195 252
196 return socket_->IsConnected(); 253 return socket_->IsConnected();
197 } 254 }
198 255
199 bool TCPSocketLibevent::IsConnectedAndIdle() const { 256 bool TCPSocketLibevent::IsConnectedAndIdle() const {
(...skipping 28 matching lines...) Expand all
228 DCHECK(socket_); 285 DCHECK(socket_);
229 DCHECK(!callback.is_null()); 286 DCHECK(!callback.is_null());
230 287
231 CompletionCallback write_callback = 288 CompletionCallback write_callback =
232 base::Bind(&TCPSocketLibevent::WriteCompleted, 289 base::Bind(&TCPSocketLibevent::WriteCompleted,
233 // Grab a reference to |buf| so that WriteCompleted() can still 290 // Grab a reference to |buf| so that WriteCompleted() can still
234 // use it when Write() completes, as otherwise, this transfers 291 // use it when Write() completes, as otherwise, this transfers
235 // ownership of buf to socket. 292 // ownership of buf to socket.
236 base::Unretained(this), make_scoped_refptr(buf), callback); 293 base::Unretained(this), make_scoped_refptr(buf), callback);
237 int rv; 294 int rv;
238 if (use_tcp_fastopen_ && !tcp_fastopen_connected_) { 295 if (use_tcp_fastopen_if_supported_ && !tcp_fastopen_connected_) {
239 rv = TcpFastOpenWrite(buf, buf_len, write_callback); 296 rv = TcpFastOpenWrite(buf, buf_len, write_callback);
240 } else { 297 } else {
241 rv = socket_->Write(buf, buf_len, write_callback); 298 rv = socket_->Write(buf, buf_len, write_callback);
242 } 299 }
243 300
244 if (rv != ERR_IO_PENDING) 301 if (rv != ERR_IO_PENDING)
245 rv = HandleWriteCompleted(buf, rv); 302 rv = HandleWriteCompleted(buf, rv);
246 return rv; 303 return rv;
247 } 304 }
248 305
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 return SetTCPNoDelay(socket_->socket_fd(), no_delay); 416 return SetTCPNoDelay(socket_->socket_fd(), no_delay);
360 } 417 }
361 418
362 void TCPSocketLibevent::Close() { 419 void TCPSocketLibevent::Close() {
363 socket_.reset(); 420 socket_.reset();
364 tcp_fastopen_connected_ = false; 421 tcp_fastopen_connected_ = false;
365 fast_open_status_ = FAST_OPEN_STATUS_UNKNOWN; 422 fast_open_status_ = FAST_OPEN_STATUS_UNKNOWN;
366 } 423 }
367 424
368 bool TCPSocketLibevent::UsingTCPFastOpen() const { 425 bool TCPSocketLibevent::UsingTCPFastOpen() const {
369 return use_tcp_fastopen_; 426 return use_tcp_fastopen_if_supported_;
427 }
428
429 void TCPSocketLibevent::EnableTCPFastOpen() {
430 if (!use_tcp_fastopen_if_supported_ && IsTCPFastOpenSupported())
431 use_tcp_fastopen_if_supported_ = true;
370 } 432 }
371 433
372 bool TCPSocketLibevent::IsValid() const { 434 bool TCPSocketLibevent::IsValid() const {
373 return socket_ != NULL && socket_->socket_fd() != kInvalidSocket; 435 return socket_ != NULL && socket_->socket_fd() != kInvalidSocket;
374 } 436 }
375 437
376 void TCPSocketLibevent::StartLoggingMultipleConnectAttempts( 438 void TCPSocketLibevent::StartLoggingMultipleConnectAttempts(
377 const AddressList& addresses) { 439 const AddressList& addresses) {
378 if (!logging_multiple_connect_attempts_) { 440 if (!logging_multiple_connect_attempts_) {
379 logging_multiple_connect_attempts_ = true; 441 logging_multiple_connect_attempts_ = true;
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
488 550
489 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT, 551 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT,
490 CreateNetLogSourceAddressCallback(storage.addr, 552 CreateNetLogSourceAddressCallback(storage.addr,
491 storage.addr_len)); 553 storage.addr_len));
492 } 554 }
493 555
494 void TCPSocketLibevent::ReadCompleted(const scoped_refptr<IOBuffer>& buf, 556 void TCPSocketLibevent::ReadCompleted(const scoped_refptr<IOBuffer>& buf,
495 const CompletionCallback& callback, 557 const CompletionCallback& callback,
496 int rv) { 558 int rv) {
497 DCHECK_NE(ERR_IO_PENDING, rv); 559 DCHECK_NE(ERR_IO_PENDING, rv);
498 // Records fast open status regardless of error in asynchronous case. 560 // Records TCP FastOpen status regardless of error in asynchronous case.
499 // TODO(rdsmith,jri): Change histogram name to indicate it could be called on 561 // TODO(rdsmith,jri): Change histogram name to indicate it could be called on
500 // error. 562 // error.
501 RecordFastOpenStatus(); 563 RecordFastOpenStatus();
502 callback.Run(HandleReadCompleted(buf, rv)); 564 callback.Run(HandleReadCompleted(buf, rv));
503 } 565 }
504 566
505 int TCPSocketLibevent::HandleReadCompleted(IOBuffer* buf, int rv) { 567 int TCPSocketLibevent::HandleReadCompleted(IOBuffer* buf, int rv) {
506 if (rv < 0) { 568 if (rv < 0) {
507 net_log_.AddEvent(NetLog::TYPE_SOCKET_READ_ERROR, 569 net_log_.AddEvent(NetLog::TYPE_SOCKET_READ_ERROR,
508 CreateNetLogSocketErrorCallback(rv, errno)); 570 CreateNetLogSocketErrorCallback(rv, errno));
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
583 if (rv != ERR_IO_PENDING) { 645 if (rv != ERR_IO_PENDING) {
584 fast_open_status_ = FAST_OPEN_ERROR; 646 fast_open_status_ = FAST_OPEN_ERROR;
585 return rv; 647 return rv;
586 } 648 }
587 649
588 fast_open_status_ = FAST_OPEN_SLOW_CONNECT_RETURN; 650 fast_open_status_ = FAST_OPEN_SLOW_CONNECT_RETURN;
589 return socket_->WaitForWrite(buf, buf_len, callback); 651 return socket_->WaitForWrite(buf, buf_len, callback);
590 } 652 }
591 653
592 void TCPSocketLibevent::RecordFastOpenStatus() { 654 void TCPSocketLibevent::RecordFastOpenStatus() {
593 if (use_tcp_fastopen_ && 655 if (use_tcp_fastopen_if_supported_ &&
594 (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN || 656 (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN ||
595 fast_open_status_ == FAST_OPEN_SLOW_CONNECT_RETURN)) { 657 fast_open_status_ == FAST_OPEN_SLOW_CONNECT_RETURN)) {
596 DCHECK_NE(FAST_OPEN_STATUS_UNKNOWN, fast_open_status_); 658 DCHECK_NE(FAST_OPEN_STATUS_UNKNOWN, fast_open_status_);
597 bool getsockopt_success(false); 659 bool getsockopt_success(false);
598 bool server_acked_data(false); 660 bool server_acked_data(false);
599 #if defined(TCP_INFO) 661 #if defined(TCP_INFO)
600 // Probe to see the if the socket used TCP Fast Open. 662 // Probe to see the if the socket used TCP FastOpen.
601 tcp_info info; 663 tcp_info info;
602 socklen_t info_len = sizeof(tcp_info); 664 socklen_t info_len = sizeof(tcp_info);
603 getsockopt_success = 665 getsockopt_success =
604 getsockopt(socket_->socket_fd(), IPPROTO_TCP, TCP_INFO, 666 getsockopt(socket_->socket_fd(), IPPROTO_TCP, TCP_INFO,
605 &info, &info_len) == 0 && 667 &info, &info_len) == 0 &&
606 info_len == sizeof(tcp_info); 668 info_len == sizeof(tcp_info);
607 server_acked_data = getsockopt_success && 669 server_acked_data = getsockopt_success &&
608 (info.tcpi_options & TCPI_OPT_SYN_DATA); 670 (info.tcpi_options & TCPI_OPT_SYN_DATA);
609 #endif 671 #endif
610 if (getsockopt_success) { 672 if (getsockopt_success) {
611 if (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN) { 673 if (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN) {
612 fast_open_status_ = (server_acked_data ? FAST_OPEN_SYN_DATA_ACK : 674 fast_open_status_ = (server_acked_data ? FAST_OPEN_SYN_DATA_ACK :
613 FAST_OPEN_SYN_DATA_NACK); 675 FAST_OPEN_SYN_DATA_NACK);
614 } else { 676 } else {
615 fast_open_status_ = (server_acked_data ? FAST_OPEN_NO_SYN_DATA_ACK : 677 fast_open_status_ = (server_acked_data ? FAST_OPEN_NO_SYN_DATA_ACK :
616 FAST_OPEN_NO_SYN_DATA_NACK); 678 FAST_OPEN_NO_SYN_DATA_NACK);
617 } 679 }
618 } else { 680 } else {
619 fast_open_status_ = (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN ? 681 fast_open_status_ = (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN ?
620 FAST_OPEN_SYN_DATA_FAILED : 682 FAST_OPEN_SYN_DATA_FAILED :
621 FAST_OPEN_NO_SYN_DATA_FAILED); 683 FAST_OPEN_NO_SYN_DATA_FAILED);
622 } 684 }
623 } 685 }
624 } 686 }
625 687
626 } // namespace net 688 } // namespace net
OLDNEW
« no previous file with comments | « net/socket/tcp_socket_libevent.h ('k') | net/socket/transport_client_socket_pool.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698