OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |