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