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

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: Rebased to master. 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 static const base::FilePath::CharType kTCPFastOpenProcFilePath[] =
mmenke 2014/09/05 19:36:42 I seem to recall reading on Chromium dev that stat
Jana 2014/09/05 20:38:57 Hmm. I don't know why this is static in the first
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,
mmenke 2014/09/05 19:36:42 Functions should generally be named after what the
Jana 2014/09/05 20:38:57 Good suggestion -- done. (RegisterTCPFastOpenInten
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),
mmenke 2014/09/05 19:36:42 File IO isn't considered slow?
Jana 2014/09/05 20:38:57 (This was the code prior to me touching it... don'
120 FROM_HERE,
121 base::Bind(SystemSupportsTCPFastOpen),
122 base::Bind(CallbackForTCPFastOpenCheck, 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_if_supported_(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 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 if (!logging_multiple_connect_attempts_) 210 if (!logging_multiple_connect_attempts_)
161 LogConnectBegin(AddressList(address)); 211 LogConnectBegin(AddressList(address));
162 212
163 net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT, 213 net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT,
164 CreateNetLogIPEndPointCallback(&address)); 214 CreateNetLogIPEndPointCallback(&address));
165 215
166 SockaddrStorage storage; 216 SockaddrStorage storage;
167 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) 217 if (!address.ToSockAddr(storage.addr, &storage.addr_len))
168 return ERR_ADDRESS_INVALID; 218 return ERR_ADDRESS_INVALID;
169 219
170 if (use_tcp_fastopen_) { 220 if (use_tcp_fastopen_if_supported_) {
171 // With TCP FastOpen, we pretend that the socket is connected. 221 // With TCP FastOpen, we pretend that the socket is connected.
172 DCHECK(!tcp_fastopen_connected_); 222 DCHECK(!tcp_fastopen_connected_);
173 socket_->SetPeerAddress(storage); 223 socket_->SetPeerAddress(storage);
174 return OK; 224 return OK;
175 } 225 }
176 226
177 int rv = socket_->Connect(storage, 227 int rv = socket_->Connect(storage,
178 base::Bind(&TCPSocketLibevent::ConnectCompleted, 228 base::Bind(&TCPSocketLibevent::ConnectCompleted,
179 base::Unretained(this), callback)); 229 base::Unretained(this), callback));
180 if (rv != ERR_IO_PENDING) 230 if (rv != ERR_IO_PENDING)
181 rv = HandleConnectCompleted(rv); 231 rv = HandleConnectCompleted(rv);
182 return rv; 232 return rv;
183 } 233 }
184 234
185 bool TCPSocketLibevent::IsConnected() const { 235 bool TCPSocketLibevent::IsConnected() const {
186 if (!socket_) 236 if (!socket_)
187 return false; 237 return false;
188 238
189 if (use_tcp_fastopen_ && !tcp_fastopen_connected_ && 239 if (use_tcp_fastopen_if_supported_ && !tcp_fastopen_connected_ &&
190 socket_->HasPeerAddress()) { 240 socket_->HasPeerAddress()) {
191 // With TCP FastOpen, we pretend that the socket is connected. 241 // With TCP FastOpen, we pretend that the socket is connected.
192 // This allows GetPeerAddress() to return peer_address_. 242 // This allows GetPeerAddress() to return peer_address_.
193 return true; 243 return true;
194 } 244 }
195 245
196 return socket_->IsConnected(); 246 return socket_->IsConnected();
197 } 247 }
198 248
199 bool TCPSocketLibevent::IsConnectedAndIdle() const { 249 bool TCPSocketLibevent::IsConnectedAndIdle() const {
(...skipping 28 matching lines...) Expand all
228 DCHECK(socket_); 278 DCHECK(socket_);
229 DCHECK(!callback.is_null()); 279 DCHECK(!callback.is_null());
230 280
231 CompletionCallback write_callback = 281 CompletionCallback write_callback =
232 base::Bind(&TCPSocketLibevent::WriteCompleted, 282 base::Bind(&TCPSocketLibevent::WriteCompleted,
233 // Grab a reference to |buf| so that WriteCompleted() can still 283 // Grab a reference to |buf| so that WriteCompleted() can still
234 // use it when Write() completes, as otherwise, this transfers 284 // use it when Write() completes, as otherwise, this transfers
235 // ownership of buf to socket. 285 // ownership of buf to socket.
236 base::Unretained(this), make_scoped_refptr(buf), callback); 286 base::Unretained(this), make_scoped_refptr(buf), callback);
237 int rv; 287 int rv;
238 if (use_tcp_fastopen_ && !tcp_fastopen_connected_) { 288 if (use_tcp_fastopen_if_supported_ && !tcp_fastopen_connected_) {
239 rv = TcpFastOpenWrite(buf, buf_len, write_callback); 289 rv = TcpFastOpenWrite(buf, buf_len, write_callback);
240 } else { 290 } else {
241 rv = socket_->Write(buf, buf_len, write_callback); 291 rv = socket_->Write(buf, buf_len, write_callback);
242 } 292 }
243 293
244 if (rv != ERR_IO_PENDING) 294 if (rv != ERR_IO_PENDING)
245 rv = HandleWriteCompleted(buf, rv); 295 rv = HandleWriteCompleted(buf, rv);
246 return rv; 296 return rv;
247 } 297 }
248 298
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 return SetTCPNoDelay(socket_->socket_fd(), no_delay); 409 return SetTCPNoDelay(socket_->socket_fd(), no_delay);
360 } 410 }
361 411
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_if_supported_;
420 }
421
422 void TCPSocketLibevent::EnableTCPFastOpen() {
423 if (!use_tcp_fastopen_if_supported_ && IsTCPFastOpenSupported())
mmenke 2014/09/05 19:36:42 The "use_tcp_fastopen_if_supported_" check isn't n
Jana 2014/09/05 20:38:57 Good catch -- Done.
424 use_tcp_fastopen_if_supported_ = true;
mmenke 2014/09/05 19:36:42 This variable should be renamed to use_tcp_fastope
Jana 2014/09/05 20:38:56 Good suggestion -- done.
370 } 425 }
371 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;
(...skipping 108 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 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
583 if (rv != ERR_IO_PENDING) { 638 if (rv != ERR_IO_PENDING) {
584 fast_open_status_ = FAST_OPEN_ERROR; 639 fast_open_status_ = FAST_OPEN_ERROR;
585 return rv; 640 return rv;
586 } 641 }
587 642
588 fast_open_status_ = FAST_OPEN_SLOW_CONNECT_RETURN; 643 fast_open_status_ = FAST_OPEN_SLOW_CONNECT_RETURN;
589 return socket_->WaitForWrite(buf, buf_len, callback); 644 return socket_->WaitForWrite(buf, buf_len, callback);
590 } 645 }
591 646
592 void TCPSocketLibevent::RecordFastOpenStatus() { 647 void TCPSocketLibevent::RecordFastOpenStatus() {
593 if (use_tcp_fastopen_ && 648 if (use_tcp_fastopen_if_supported_ &&
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