Home | History | Annotate | Download | only in socket
      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 
     33 namespace net {
     34 
     35 namespace {
     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 
     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`.
     47 bool 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.
     54 bool 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.
     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 
    105 }  // namespace
    106 
    107 //-----------------------------------------------------------------------------
    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 
    129 TCPSocketLibevent::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 
    140 TCPSocketLibevent::~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 
    148 int 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 
    157 int 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 
    175 int 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 
    185 int TCPSocketLibevent::Listen(int backlog) {
    186   DCHECK(socket_);
    187   return socket_->Listen(backlog);
    188 }
    189 
    190 int 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 
    209 int 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 
    238 bool 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 
    252 bool 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 
    258 int 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 
    278 int 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 
    302 int 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 
    319 int 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 
    336 int TCPSocketLibevent::SetDefaultOptionsForServer() {
    337   DCHECK(socket_);
    338   return SetAddressReuse(true);
    339 }
    340 
    341 void 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 
    367 int 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 
    391 int 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 
    398 int 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 
    405 bool TCPSocketLibevent::SetKeepAlive(bool enable, int delay) {
    406   DCHECK(socket_);
    407   return SetTCPKeepAlive(socket_->socket_fd(), enable, delay);
    408 }
    409 
    410 bool TCPSocketLibevent::SetNoDelay(bool no_delay) {
    411   DCHECK(socket_);
    412   return SetTCPNoDelay(socket_->socket_fd(), no_delay);
    413 }
    414 
    415 void TCPSocketLibevent::Close() {
    416   socket_.reset();
    417   tcp_fastopen_connected_ = false;
    418   fast_open_status_ = FAST_OPEN_STATUS_UNKNOWN;
    419 }
    420 
    421 bool TCPSocketLibevent::UsingTCPFastOpen() const {
    422   return use_tcp_fastopen_;
    423 }
    424 
    425 void TCPSocketLibevent::EnableTCPFastOpenIfSupported() {
    426   if (IsTCPFastOpenSupported())
    427     use_tcp_fastopen_ = true;
    428 }
    429 
    430 bool TCPSocketLibevent::IsValid() const {
    431   return socket_ != NULL && socket_->socket_fd() != kInvalidSocket;
    432 }
    433 
    434 void 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 
    444 void 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 
    453 void 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 
    462 int 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 
    479 int 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 
    497 void TCPSocketLibevent::ConnectCompleted(const CompletionCallback& callback,
    498                                          int rv) const {
    499   DCHECK_NE(ERR_IO_PENDING, rv);
    500   callback.Run(HandleConnectCompleted(rv));
    501 }
    502 
    503 int 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 
    522 void 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 
    530 void 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 
    552 void 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 
    563 int 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 
    577 void 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 
    584 int 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 
    598 int 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 
    650 void 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