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