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

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: Fixing linker error for Windows. 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
« no previous file with comments | « net/socket/tcp_socket_libevent.h ('k') | net/socket/tcp_socket_win.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
31 namespace net { 33 namespace net {
32 34
33 namespace { 35 namespace {
34 36
37 // True if OS supports TCP FastOpen.
38 bool g_tcp_fastopen_supported = false;
39 // True if TCP FastOpen is user-enabled for all connections.
40 // TODO(jri): Change global variable to param in HttpNetworkSession::Params.
41 bool g_tcp_fastopen_user_enabled = false;
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;
41 int error = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); 49 int error = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
42 return error == 0; 50 return error == 0;
43 } 51 }
44 52
(...skipping 17 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
72 } // namespace 105 } // namespace
73 106
74 //----------------------------------------------------------------------------- 107 //-----------------------------------------------------------------------------
75 108
109 bool IsTCPFastOpenSupported() {
110 return g_tcp_fastopen_supported;
111 }
112
113 bool IsTCPFastOpenUserEnabled() {
114 return g_tcp_fastopen_user_enabled;
115 }
116
117 // This is asynchronous because it needs to do file IO, and it isn't allowed to
118 // do that on the IO thread.
119 void CheckSupportAndMaybeEnableTCPFastOpen(bool user_enabled) {
120 #if defined(OS_LINUX) || defined(OS_ANDROID)
121 base::PostTaskAndReplyWithResult(
122 base::WorkerPool::GetTaskRunner(/*task_is_slow=*/false).get(),
123 FROM_HERE,
124 base::Bind(SystemSupportsTCPFastOpen),
125 base::Bind(RegisterTCPFastOpenIntentAndSupport, user_enabled));
126 #endif
127 }
128
76 TCPSocketLibevent::TCPSocketLibevent(NetLog* net_log, 129 TCPSocketLibevent::TCPSocketLibevent(NetLog* net_log,
77 const NetLog::Source& source) 130 const NetLog::Source& source)
78 : use_tcp_fastopen_(IsTCPFastOpenEnabled()), 131 : use_tcp_fastopen_(false),
79 tcp_fastopen_connected_(false), 132 tcp_fastopen_connected_(false),
80 fast_open_status_(FAST_OPEN_STATUS_UNKNOWN), 133 fast_open_status_(FAST_OPEN_STATUS_UNKNOWN),
81 logging_multiple_connect_attempts_(false), 134 logging_multiple_connect_attempts_(false),
82 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) { 135 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
83 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, 136 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
84 source.ToEventParametersCallback()); 137 source.ToEventParametersCallback());
85 } 138 }
86 139
87 TCPSocketLibevent::~TCPSocketLibevent() { 140 TCPSocketLibevent::~TCPSocketLibevent() {
88 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE); 141 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 void TCPSocketLibevent::Close() { 415 void TCPSocketLibevent::Close() {
363 socket_.reset(); 416 socket_.reset();
364 tcp_fastopen_connected_ = false; 417 tcp_fastopen_connected_ = false;
365 fast_open_status_ = FAST_OPEN_STATUS_UNKNOWN; 418 fast_open_status_ = FAST_OPEN_STATUS_UNKNOWN;
366 } 419 }
367 420
368 bool TCPSocketLibevent::UsingTCPFastOpen() const { 421 bool TCPSocketLibevent::UsingTCPFastOpen() const {
369 return use_tcp_fastopen_; 422 return use_tcp_fastopen_;
370 } 423 }
371 424
425 void TCPSocketLibevent::EnableTCPFastOpenIfSupported() {
426 if (IsTCPFastOpenSupported())
427 use_tcp_fastopen_ = true;
428 }
429
372 bool TCPSocketLibevent::IsValid() const { 430 bool TCPSocketLibevent::IsValid() const {
373 return socket_ != NULL && socket_->socket_fd() != kInvalidSocket; 431 return socket_ != NULL && socket_->socket_fd() != kInvalidSocket;
374 } 432 }
375 433
376 void TCPSocketLibevent::StartLoggingMultipleConnectAttempts( 434 void TCPSocketLibevent::StartLoggingMultipleConnectAttempts(
377 const AddressList& addresses) { 435 const AddressList& addresses) {
378 if (!logging_multiple_connect_attempts_) { 436 if (!logging_multiple_connect_attempts_) {
379 logging_multiple_connect_attempts_ = true; 437 logging_multiple_connect_attempts_ = true;
380 LogConnectBegin(addresses); 438 LogConnectBegin(addresses);
381 } else { 439 } else {
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
488 546
489 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT, 547 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT,
490 CreateNetLogSourceAddressCallback(storage.addr, 548 CreateNetLogSourceAddressCallback(storage.addr,
491 storage.addr_len)); 549 storage.addr_len));
492 } 550 }
493 551
494 void TCPSocketLibevent::ReadCompleted(const scoped_refptr<IOBuffer>& buf, 552 void TCPSocketLibevent::ReadCompleted(const scoped_refptr<IOBuffer>& buf,
495 const CompletionCallback& callback, 553 const CompletionCallback& callback,
496 int rv) { 554 int rv) {
497 DCHECK_NE(ERR_IO_PENDING, rv); 555 DCHECK_NE(ERR_IO_PENDING, rv);
498 // Records fast open status regardless of error in asynchronous case. 556 // Records TCP FastOpen status regardless of error in asynchronous case.
499 // TODO(rdsmith,jri): Change histogram name to indicate it could be called on 557 // TODO(rdsmith,jri): Change histogram name to indicate it could be called on
500 // error. 558 // error.
501 RecordFastOpenStatus(); 559 RecordFastOpenStatus();
502 callback.Run(HandleReadCompleted(buf.get(), rv)); 560 callback.Run(HandleReadCompleted(buf.get(), rv));
503 } 561 }
504 562
505 int TCPSocketLibevent::HandleReadCompleted(IOBuffer* buf, int rv) { 563 int TCPSocketLibevent::HandleReadCompleted(IOBuffer* buf, int rv) {
506 if (rv < 0) { 564 if (rv < 0) {
507 net_log_.AddEvent(NetLog::TYPE_SOCKET_READ_ERROR, 565 net_log_.AddEvent(NetLog::TYPE_SOCKET_READ_ERROR,
508 CreateNetLogSocketErrorCallback(rv, errno)); 566 CreateNetLogSocketErrorCallback(rv, errno));
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 } 648 }
591 649
592 void TCPSocketLibevent::RecordFastOpenStatus() { 650 void TCPSocketLibevent::RecordFastOpenStatus() {
593 if (use_tcp_fastopen_ && 651 if (use_tcp_fastopen_ &&
594 (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN || 652 (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN ||
595 fast_open_status_ == FAST_OPEN_SLOW_CONNECT_RETURN)) { 653 fast_open_status_ == FAST_OPEN_SLOW_CONNECT_RETURN)) {
596 DCHECK_NE(FAST_OPEN_STATUS_UNKNOWN, fast_open_status_); 654 DCHECK_NE(FAST_OPEN_STATUS_UNKNOWN, fast_open_status_);
597 bool getsockopt_success(false); 655 bool getsockopt_success(false);
598 bool server_acked_data(false); 656 bool server_acked_data(false);
599 #if defined(TCP_INFO) 657 #if defined(TCP_INFO)
600 // Probe to see the if the socket used TCP Fast Open. 658 // Probe to see the if the socket used TCP FastOpen.
601 tcp_info info; 659 tcp_info info;
602 socklen_t info_len = sizeof(tcp_info); 660 socklen_t info_len = sizeof(tcp_info);
603 getsockopt_success = 661 getsockopt_success =
604 getsockopt(socket_->socket_fd(), IPPROTO_TCP, TCP_INFO, 662 getsockopt(socket_->socket_fd(), IPPROTO_TCP, TCP_INFO,
605 &info, &info_len) == 0 && 663 &info, &info_len) == 0 &&
606 info_len == sizeof(tcp_info); 664 info_len == sizeof(tcp_info);
607 server_acked_data = getsockopt_success && 665 server_acked_data = getsockopt_success &&
608 (info.tcpi_options & TCPI_OPT_SYN_DATA); 666 (info.tcpi_options & TCPI_OPT_SYN_DATA);
609 #endif 667 #endif
610 if (getsockopt_success) { 668 if (getsockopt_success) {
611 if (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN) { 669 if (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN) {
612 fast_open_status_ = (server_acked_data ? FAST_OPEN_SYN_DATA_ACK : 670 fast_open_status_ = (server_acked_data ? FAST_OPEN_SYN_DATA_ACK :
613 FAST_OPEN_SYN_DATA_NACK); 671 FAST_OPEN_SYN_DATA_NACK);
614 } else { 672 } else {
615 fast_open_status_ = (server_acked_data ? FAST_OPEN_NO_SYN_DATA_ACK : 673 fast_open_status_ = (server_acked_data ? FAST_OPEN_NO_SYN_DATA_ACK :
616 FAST_OPEN_NO_SYN_DATA_NACK); 674 FAST_OPEN_NO_SYN_DATA_NACK);
617 } 675 }
618 } else { 676 } else {
619 fast_open_status_ = (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN ? 677 fast_open_status_ = (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN ?
620 FAST_OPEN_SYN_DATA_FAILED : 678 FAST_OPEN_SYN_DATA_FAILED :
621 FAST_OPEN_NO_SYN_DATA_FAILED); 679 FAST_OPEN_NO_SYN_DATA_FAILED);
622 } 680 }
623 } 681 }
624 } 682 }
625 683
626 } // namespace net 684 } // namespace net
OLDNEW
« no previous file with comments | « net/socket/tcp_socket_libevent.h ('k') | net/socket/tcp_socket_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698