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 3// found in the LICENSE file. 4 5#include "net/socket/tcp_socket.h" 6 7#include <errno.h> 8#include <netinet/tcp.h> 9#include <sys/socket.h> 10 11#include "base/bind.h" 12#include "base/logging.h" 13#include "base/metrics/histogram.h" 14#include "base/metrics/stats_counters.h" 15#include "base/posix/eintr_wrapper.h" 16#include "base/task_runner_util.h" 17#include "base/threading/worker_pool.h" 18#include "net/base/address_list.h" 19#include "net/base/connection_type_histograms.h" 20#include "net/base/io_buffer.h" 21#include "net/base/ip_endpoint.h" 22#include "net/base/net_errors.h" 23#include "net/base/net_util.h" 24#include "net/base/network_change_notifier.h" 25#include "net/socket/socket_libevent.h" 26#include "net/socket/socket_net_log_params.h" 27 28// If we don't have a definition for TCPI_OPT_SYN_DATA, create one. 29#ifndef TCPI_OPT_SYN_DATA 30#define TCPI_OPT_SYN_DATA 32 31#endif 32 33namespace net { 34 35namespace { 36 37// True if OS supports TCP FastOpen. 38bool 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. 41bool g_tcp_fastopen_user_enabled = false; 42 43// SetTCPNoDelay turns on/off buffering in the kernel. By default, TCP sockets 44// will wait up to 200ms for more data to complete a packet before transmitting. 45// After calling this function, the kernel will not wait. See TCP_NODELAY in 46// `man 7 tcp`. 47bool SetTCPNoDelay(int fd, bool no_delay) { 48 int on = no_delay ? 1 : 0; 49 int error = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); 50 return error == 0; 51} 52 53// SetTCPKeepAlive sets SO_KEEPALIVE. 54bool SetTCPKeepAlive(int fd, bool enable, int delay) { 55 int on = enable ? 1 : 0; 56 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on))) { 57 PLOG(ERROR) << "Failed to set SO_KEEPALIVE on fd: " << fd; 58 return false; 59 } 60 61 // If we disabled TCP keep alive, our work is done here. 62 if (!enable) 63 return true; 64 65#if defined(OS_LINUX) || defined(OS_ANDROID) 66 // Set seconds until first TCP keep alive. 67 if (setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) { 68 PLOG(ERROR) << "Failed to set TCP_KEEPIDLE on fd: " << fd; 69 return false; 70 } 71 // Set seconds between TCP keep alives. 72 if (setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &delay, sizeof(delay))) { 73 PLOG(ERROR) << "Failed to set TCP_KEEPINTVL on fd: " << fd; 74 return false; 75 } 76#endif 77 return true; 78} 79 80#if defined(OS_LINUX) || defined(OS_ANDROID) 81// Checks if the kernel supports TCP FastOpen. 82bool 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 98void 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 105} // namespace 106 107//----------------------------------------------------------------------------- 108 109bool IsTCPFastOpenSupported() { 110 return g_tcp_fastopen_supported; 111} 112 113bool 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. 119void 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 129TCPSocketLibevent::TCPSocketLibevent(NetLog* net_log, 130 const NetLog::Source& source) 131 : use_tcp_fastopen_(false), 132 tcp_fastopen_connected_(false), 133 fast_open_status_(FAST_OPEN_STATUS_UNKNOWN), 134 logging_multiple_connect_attempts_(false), 135 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) { 136 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, 137 source.ToEventParametersCallback()); 138} 139 140TCPSocketLibevent::~TCPSocketLibevent() { 141 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE); 142 if (tcp_fastopen_connected_) { 143 UMA_HISTOGRAM_ENUMERATION("Net.TcpFastOpenSocketConnection", 144 fast_open_status_, FAST_OPEN_MAX_VALUE); 145 } 146} 147 148int TCPSocketLibevent::Open(AddressFamily family) { 149 DCHECK(!socket_); 150 socket_.reset(new SocketLibevent); 151 int rv = socket_->Open(ConvertAddressFamily(family)); 152 if (rv != OK) 153 socket_.reset(); 154 return rv; 155} 156 157int TCPSocketLibevent::AdoptConnectedSocket(int socket_fd, 158 const IPEndPoint& peer_address) { 159 DCHECK(!socket_); 160 161 SockaddrStorage storage; 162 if (!peer_address.ToSockAddr(storage.addr, &storage.addr_len) && 163 // For backward compatibility, allows the empty address. 164 !(peer_address == IPEndPoint())) { 165 return ERR_ADDRESS_INVALID; 166 } 167 168 socket_.reset(new SocketLibevent); 169 int rv = socket_->AdoptConnectedSocket(socket_fd, storage); 170 if (rv != OK) 171 socket_.reset(); 172 return rv; 173} 174 175int TCPSocketLibevent::Bind(const IPEndPoint& address) { 176 DCHECK(socket_); 177 178 SockaddrStorage storage; 179 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) 180 return ERR_ADDRESS_INVALID; 181 182 return socket_->Bind(storage); 183} 184 185int TCPSocketLibevent::Listen(int backlog) { 186 DCHECK(socket_); 187 return socket_->Listen(backlog); 188} 189 190int TCPSocketLibevent::Accept(scoped_ptr<TCPSocketLibevent>* tcp_socket, 191 IPEndPoint* address, 192 const CompletionCallback& callback) { 193 DCHECK(tcp_socket); 194 DCHECK(!callback.is_null()); 195 DCHECK(socket_); 196 DCHECK(!accept_socket_); 197 198 net_log_.BeginEvent(NetLog::TYPE_TCP_ACCEPT); 199 200 int rv = socket_->Accept( 201 &accept_socket_, 202 base::Bind(&TCPSocketLibevent::AcceptCompleted, 203 base::Unretained(this), tcp_socket, address, callback)); 204 if (rv != ERR_IO_PENDING) 205 rv = HandleAcceptCompleted(tcp_socket, address, rv); 206 return rv; 207} 208 209int TCPSocketLibevent::Connect(const IPEndPoint& address, 210 const CompletionCallback& callback) { 211 DCHECK(socket_); 212 213 if (!logging_multiple_connect_attempts_) 214 LogConnectBegin(AddressList(address)); 215 216 net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT, 217 CreateNetLogIPEndPointCallback(&address)); 218 219 SockaddrStorage storage; 220 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) 221 return ERR_ADDRESS_INVALID; 222 223 if (use_tcp_fastopen_) { 224 // With TCP FastOpen, we pretend that the socket is connected. 225 DCHECK(!tcp_fastopen_connected_); 226 socket_->SetPeerAddress(storage); 227 return OK; 228 } 229 230 int rv = socket_->Connect(storage, 231 base::Bind(&TCPSocketLibevent::ConnectCompleted, 232 base::Unretained(this), callback)); 233 if (rv != ERR_IO_PENDING) 234 rv = HandleConnectCompleted(rv); 235 return rv; 236} 237 238bool TCPSocketLibevent::IsConnected() const { 239 if (!socket_) 240 return false; 241 242 if (use_tcp_fastopen_ && !tcp_fastopen_connected_ && 243 socket_->HasPeerAddress()) { 244 // With TCP FastOpen, we pretend that the socket is connected. 245 // This allows GetPeerAddress() to return peer_address_. 246 return true; 247 } 248 249 return socket_->IsConnected(); 250} 251 252bool TCPSocketLibevent::IsConnectedAndIdle() const { 253 // TODO(wtc): should we also handle the TCP FastOpen case here, 254 // as we do in IsConnected()? 255 return socket_ && socket_->IsConnectedAndIdle(); 256} 257 258int TCPSocketLibevent::Read(IOBuffer* buf, 259 int buf_len, 260 const CompletionCallback& callback) { 261 DCHECK(socket_); 262 DCHECK(!callback.is_null()); 263 264 int rv = socket_->Read( 265 buf, buf_len, 266 base::Bind(&TCPSocketLibevent::ReadCompleted, 267 // Grab a reference to |buf| so that ReadCompleted() can still 268 // use it when Read() completes, as otherwise, this transfers 269 // ownership of buf to socket. 270 base::Unretained(this), make_scoped_refptr(buf), callback)); 271 if (rv >= 0) 272 RecordFastOpenStatus(); 273 if (rv != ERR_IO_PENDING) 274 rv = HandleReadCompleted(buf, rv); 275 return rv; 276} 277 278int TCPSocketLibevent::Write(IOBuffer* buf, 279 int buf_len, 280 const CompletionCallback& callback) { 281 DCHECK(socket_); 282 DCHECK(!callback.is_null()); 283 284 CompletionCallback write_callback = 285 base::Bind(&TCPSocketLibevent::WriteCompleted, 286 // Grab a reference to |buf| so that WriteCompleted() can still 287 // use it when Write() completes, as otherwise, this transfers 288 // ownership of buf to socket. 289 base::Unretained(this), make_scoped_refptr(buf), callback); 290 int rv; 291 if (use_tcp_fastopen_ && !tcp_fastopen_connected_) { 292 rv = TcpFastOpenWrite(buf, buf_len, write_callback); 293 } else { 294 rv = socket_->Write(buf, buf_len, write_callback); 295 } 296 297 if (rv != ERR_IO_PENDING) 298 rv = HandleWriteCompleted(buf, rv); 299 return rv; 300} 301 302int TCPSocketLibevent::GetLocalAddress(IPEndPoint* address) const { 303 DCHECK(address); 304 305 if (!socket_) 306 return ERR_SOCKET_NOT_CONNECTED; 307 308 SockaddrStorage storage; 309 int rv = socket_->GetLocalAddress(&storage); 310 if (rv != OK) 311 return rv; 312 313 if (!address->FromSockAddr(storage.addr, storage.addr_len)) 314 return ERR_ADDRESS_INVALID; 315 316 return OK; 317} 318 319int TCPSocketLibevent::GetPeerAddress(IPEndPoint* address) const { 320 DCHECK(address); 321 322 if (!IsConnected()) 323 return ERR_SOCKET_NOT_CONNECTED; 324 325 SockaddrStorage storage; 326 int rv = socket_->GetPeerAddress(&storage); 327 if (rv != OK) 328 return rv; 329 330 if (!address->FromSockAddr(storage.addr, storage.addr_len)) 331 return ERR_ADDRESS_INVALID; 332 333 return OK; 334} 335 336int TCPSocketLibevent::SetDefaultOptionsForServer() { 337 DCHECK(socket_); 338 return SetAddressReuse(true); 339} 340 341void TCPSocketLibevent::SetDefaultOptionsForClient() { 342 DCHECK(socket_); 343 344 // This mirrors the behaviour on Windows. See the comment in 345 // tcp_socket_win.cc after searching for "NODELAY". 346 // If SetTCPNoDelay fails, we don't care. 347 SetTCPNoDelay(socket_->socket_fd(), true); 348 349 // TCP keep alive wakes up the radio, which is expensive on mobile. Do not 350 // enable it there. It's useful to prevent TCP middleboxes from timing out 351 // connection mappings. Packets for timed out connection mappings at 352 // middleboxes will either lead to: 353 // a) Middleboxes sending TCP RSTs. It's up to higher layers to check for this 354 // and retry. The HTTP network transaction code does this. 355 // b) Middleboxes just drop the unrecognized TCP packet. This leads to the TCP 356 // stack retransmitting packets per TCP stack retransmission timeouts, which 357 // are very high (on the order of seconds). Given the number of 358 // retransmissions required before killing the connection, this can lead to 359 // tens of seconds or even minutes of delay, depending on OS. 360#if !defined(OS_ANDROID) && !defined(OS_IOS) 361 const int kTCPKeepAliveSeconds = 45; 362 363 SetTCPKeepAlive(socket_->socket_fd(), true, kTCPKeepAliveSeconds); 364#endif 365} 366 367int TCPSocketLibevent::SetAddressReuse(bool allow) { 368 DCHECK(socket_); 369 370 // SO_REUSEADDR is useful for server sockets to bind to a recently unbound 371 // port. When a socket is closed, the end point changes its state to TIME_WAIT 372 // and wait for 2 MSL (maximum segment lifetime) to ensure the remote peer 373 // acknowledges its closure. For server sockets, it is usually safe to 374 // bind to a TIME_WAIT end point immediately, which is a widely adopted 375 // behavior. 376 // 377 // Note that on *nix, SO_REUSEADDR does not enable the TCP socket to bind to 378 // an end point that is already bound by another socket. To do that one must 379 // set SO_REUSEPORT instead. This option is not provided on Linux prior 380 // to 3.9. 381 // 382 // SO_REUSEPORT is provided in MacOS X and iOS. 383 int boolean_value = allow ? 1 : 0; 384 int rv = setsockopt(socket_->socket_fd(), SOL_SOCKET, SO_REUSEADDR, 385 &boolean_value, sizeof(boolean_value)); 386 if (rv < 0) 387 return MapSystemError(errno); 388 return OK; 389} 390 391int TCPSocketLibevent::SetReceiveBufferSize(int32 size) { 392 DCHECK(socket_); 393 int rv = setsockopt(socket_->socket_fd(), SOL_SOCKET, SO_RCVBUF, 394 reinterpret_cast<const char*>(&size), sizeof(size)); 395 return (rv == 0) ? OK : MapSystemError(errno); 396} 397 398int TCPSocketLibevent::SetSendBufferSize(int32 size) { 399 DCHECK(socket_); 400 int rv = setsockopt(socket_->socket_fd(), SOL_SOCKET, SO_SNDBUF, 401 reinterpret_cast<const char*>(&size), sizeof(size)); 402 return (rv == 0) ? OK : MapSystemError(errno); 403} 404 405bool TCPSocketLibevent::SetKeepAlive(bool enable, int delay) { 406 DCHECK(socket_); 407 return SetTCPKeepAlive(socket_->socket_fd(), enable, delay); 408} 409 410bool TCPSocketLibevent::SetNoDelay(bool no_delay) { 411 DCHECK(socket_); 412 return SetTCPNoDelay(socket_->socket_fd(), no_delay); 413} 414 415void TCPSocketLibevent::Close() { 416 socket_.reset(); 417 tcp_fastopen_connected_ = false; 418 fast_open_status_ = FAST_OPEN_STATUS_UNKNOWN; 419} 420 421bool TCPSocketLibevent::UsingTCPFastOpen() const { 422 return use_tcp_fastopen_; 423} 424 425void TCPSocketLibevent::EnableTCPFastOpenIfSupported() { 426 if (IsTCPFastOpenSupported()) 427 use_tcp_fastopen_ = true; 428} 429 430bool TCPSocketLibevent::IsValid() const { 431 return socket_ != NULL && socket_->socket_fd() != kInvalidSocket; 432} 433 434void TCPSocketLibevent::StartLoggingMultipleConnectAttempts( 435 const AddressList& addresses) { 436 if (!logging_multiple_connect_attempts_) { 437 logging_multiple_connect_attempts_ = true; 438 LogConnectBegin(addresses); 439 } else { 440 NOTREACHED(); 441 } 442} 443 444void TCPSocketLibevent::EndLoggingMultipleConnectAttempts(int net_error) { 445 if (logging_multiple_connect_attempts_) { 446 LogConnectEnd(net_error); 447 logging_multiple_connect_attempts_ = false; 448 } else { 449 NOTREACHED(); 450 } 451} 452 453void TCPSocketLibevent::AcceptCompleted( 454 scoped_ptr<TCPSocketLibevent>* tcp_socket, 455 IPEndPoint* address, 456 const CompletionCallback& callback, 457 int rv) { 458 DCHECK_NE(ERR_IO_PENDING, rv); 459 callback.Run(HandleAcceptCompleted(tcp_socket, address, rv)); 460} 461 462int TCPSocketLibevent::HandleAcceptCompleted( 463 scoped_ptr<TCPSocketLibevent>* tcp_socket, 464 IPEndPoint* address, 465 int rv) { 466 if (rv == OK) 467 rv = BuildTcpSocketLibevent(tcp_socket, address); 468 469 if (rv == OK) { 470 net_log_.EndEvent(NetLog::TYPE_TCP_ACCEPT, 471 CreateNetLogIPEndPointCallback(address)); 472 } else { 473 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, rv); 474 } 475 476 return rv; 477} 478 479int TCPSocketLibevent::BuildTcpSocketLibevent( 480 scoped_ptr<TCPSocketLibevent>* tcp_socket, 481 IPEndPoint* address) { 482 DCHECK(accept_socket_); 483 484 SockaddrStorage storage; 485 if (accept_socket_->GetPeerAddress(&storage) != OK || 486 !address->FromSockAddr(storage.addr, storage.addr_len)) { 487 accept_socket_.reset(); 488 return ERR_ADDRESS_INVALID; 489 } 490 491 tcp_socket->reset(new TCPSocketLibevent(net_log_.net_log(), 492 net_log_.source())); 493 (*tcp_socket)->socket_.reset(accept_socket_.release()); 494 return OK; 495} 496 497void TCPSocketLibevent::ConnectCompleted(const CompletionCallback& callback, 498 int rv) const { 499 DCHECK_NE(ERR_IO_PENDING, rv); 500 callback.Run(HandleConnectCompleted(rv)); 501} 502 503int TCPSocketLibevent::HandleConnectCompleted(int rv) const { 504 // Log the end of this attempt (and any OS error it threw). 505 if (rv != OK) { 506 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT, 507 NetLog::IntegerCallback("os_error", errno)); 508 } else { 509 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT); 510 } 511 512 // Give a more specific error when the user is offline. 513 if (rv == ERR_ADDRESS_UNREACHABLE && NetworkChangeNotifier::IsOffline()) 514 rv = ERR_INTERNET_DISCONNECTED; 515 516 if (!logging_multiple_connect_attempts_) 517 LogConnectEnd(rv); 518 519 return rv; 520} 521 522void TCPSocketLibevent::LogConnectBegin(const AddressList& addresses) const { 523 base::StatsCounter connects("tcp.connect"); 524 connects.Increment(); 525 526 net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT, 527 addresses.CreateNetLogCallback()); 528} 529 530void TCPSocketLibevent::LogConnectEnd(int net_error) const { 531 if (net_error != OK) { 532 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT, net_error); 533 return; 534 } 535 536 UpdateConnectionTypeHistograms(CONNECTION_ANY); 537 538 SockaddrStorage storage; 539 int rv = socket_->GetLocalAddress(&storage); 540 if (rv != OK) { 541 PLOG(ERROR) << "GetLocalAddress() [rv: " << rv << "] error: "; 542 NOTREACHED(); 543 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT, rv); 544 return; 545 } 546 547 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT, 548 CreateNetLogSourceAddressCallback(storage.addr, 549 storage.addr_len)); 550} 551 552void TCPSocketLibevent::ReadCompleted(const scoped_refptr<IOBuffer>& buf, 553 const CompletionCallback& callback, 554 int rv) { 555 DCHECK_NE(ERR_IO_PENDING, rv); 556 // Records TCP FastOpen status regardless of error in asynchronous case. 557 // TODO(rdsmith,jri): Change histogram name to indicate it could be called on 558 // error. 559 RecordFastOpenStatus(); 560 callback.Run(HandleReadCompleted(buf.get(), rv)); 561} 562 563int TCPSocketLibevent::HandleReadCompleted(IOBuffer* buf, int rv) { 564 if (rv < 0) { 565 net_log_.AddEvent(NetLog::TYPE_SOCKET_READ_ERROR, 566 CreateNetLogSocketErrorCallback(rv, errno)); 567 return rv; 568 } 569 570 base::StatsCounter read_bytes("tcp.read_bytes"); 571 read_bytes.Add(rv); 572 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, rv, 573 buf->data()); 574 return rv; 575} 576 577void TCPSocketLibevent::WriteCompleted(const scoped_refptr<IOBuffer>& buf, 578 const CompletionCallback& callback, 579 int rv) const { 580 DCHECK_NE(ERR_IO_PENDING, rv); 581 callback.Run(HandleWriteCompleted(buf.get(), rv)); 582} 583 584int TCPSocketLibevent::HandleWriteCompleted(IOBuffer* buf, int rv) const { 585 if (rv < 0) { 586 net_log_.AddEvent(NetLog::TYPE_SOCKET_WRITE_ERROR, 587 CreateNetLogSocketErrorCallback(rv, errno)); 588 return rv; 589 } 590 591 base::StatsCounter write_bytes("tcp.write_bytes"); 592 write_bytes.Add(rv); 593 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, rv, 594 buf->data()); 595 return rv; 596} 597 598int TCPSocketLibevent::TcpFastOpenWrite( 599 IOBuffer* buf, 600 int buf_len, 601 const CompletionCallback& callback) { 602 SockaddrStorage storage; 603 int rv = socket_->GetPeerAddress(&storage); 604 if (rv != OK) 605 return rv; 606 607 int flags = 0x20000000; // Magic flag to enable TCP_FASTOPEN. 608#if defined(OS_LINUX) || defined(OS_ANDROID) 609 // sendto() will fail with EPIPE when the system doesn't support TCP Fast 610 // Open. Theoretically that shouldn't happen since the caller should check 611 // for system support on startup, but users may dynamically disable TCP Fast 612 // Open via sysctl. 613 flags |= MSG_NOSIGNAL; 614#endif // defined(OS_LINUX) || defined(OS_ANDROID) 615 rv = HANDLE_EINTR(sendto(socket_->socket_fd(), 616 buf->data(), 617 buf_len, 618 flags, 619 storage.addr, 620 storage.addr_len)); 621 tcp_fastopen_connected_ = true; 622 623 if (rv >= 0) { 624 fast_open_status_ = FAST_OPEN_FAST_CONNECT_RETURN; 625 return rv; 626 } 627 628 DCHECK_NE(EPIPE, errno); 629 630 // If errno == EINPROGRESS, that means the kernel didn't have a cookie 631 // and would block. The kernel is internally doing a connect() though. 632 // Remap EINPROGRESS to EAGAIN so we treat this the same as our other 633 // asynchronous cases. Note that the user buffer has not been copied to 634 // kernel space. 635 if (errno == EINPROGRESS) { 636 rv = ERR_IO_PENDING; 637 } else { 638 rv = MapSystemError(errno); 639 } 640 641 if (rv != ERR_IO_PENDING) { 642 fast_open_status_ = FAST_OPEN_ERROR; 643 return rv; 644 } 645 646 fast_open_status_ = FAST_OPEN_SLOW_CONNECT_RETURN; 647 return socket_->WaitForWrite(buf, buf_len, callback); 648} 649 650void TCPSocketLibevent::RecordFastOpenStatus() { 651 if (use_tcp_fastopen_ && 652 (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN || 653 fast_open_status_ == FAST_OPEN_SLOW_CONNECT_RETURN)) { 654 DCHECK_NE(FAST_OPEN_STATUS_UNKNOWN, fast_open_status_); 655 bool getsockopt_success(false); 656 bool server_acked_data(false); 657#if defined(TCP_INFO) 658 // Probe to see the if the socket used TCP FastOpen. 659 tcp_info info; 660 socklen_t info_len = sizeof(tcp_info); 661 getsockopt_success = 662 getsockopt(socket_->socket_fd(), IPPROTO_TCP, TCP_INFO, 663 &info, &info_len) == 0 && 664 info_len == sizeof(tcp_info); 665 server_acked_data = getsockopt_success && 666 (info.tcpi_options & TCPI_OPT_SYN_DATA); 667#endif 668 if (getsockopt_success) { 669 if (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN) { 670 fast_open_status_ = (server_acked_data ? FAST_OPEN_SYN_DATA_ACK : 671 FAST_OPEN_SYN_DATA_NACK); 672 } else { 673 fast_open_status_ = (server_acked_data ? FAST_OPEN_NO_SYN_DATA_ACK : 674 FAST_OPEN_NO_SYN_DATA_NACK); 675 } 676 } else { 677 fast_open_status_ = (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN ? 678 FAST_OPEN_SYN_DATA_FAILED : 679 FAST_OPEN_NO_SYN_DATA_FAILED); 680 } 681 } 682} 683 684} // namespace net 685