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.
5 #include "net/socket/tcp_socket.h"
10 #include <netinet/in.h>
11 #include <netinet/tcp.h>
12 #include <sys/socket.h>
14 #include "base/callback_helpers.h"
15 #include "base/logging.h"
16 #include "base/metrics/histogram.h"
17 #include "base/metrics/stats_counters.h"
18 #include "base/posix/eintr_wrapper.h"
19 #include "build/build_config.h"
20 #include "net/base/address_list.h"
21 #include "net/base/connection_type_histograms.h"
22 #include "net/base/io_buffer.h"
23 #include "net/base/ip_endpoint.h"
24 #include "net/base/net_errors.h"
25 #include "net/base/net_util.h"
26 #include "net/base/network_change_notifier.h"
27 #include "net/socket/socket_net_log_params.h"
29 // If we don't have a definition for TCPI_OPT_SYN_DATA, create one.
30 #ifndef TCPI_OPT_SYN_DATA
31 #define TCPI_OPT_SYN_DATA 32
38 const int kTCPKeepAliveSeconds
= 45;
40 // SetTCPNoDelay turns on/off buffering in the kernel. By default, TCP sockets
41 // will wait up to 200ms for more data to complete a packet before transmitting.
42 // After calling this function, the kernel will not wait. See TCP_NODELAY in
44 bool SetTCPNoDelay(int fd
, bool no_delay
) {
45 int on
= no_delay
? 1 : 0;
46 int error
= setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, &on
, sizeof(on
));
50 // SetTCPKeepAlive sets SO_KEEPALIVE.
51 bool SetTCPKeepAlive(int fd
, bool enable
, int delay
) {
52 int on
= enable
? 1 : 0;
53 if (setsockopt(fd
, SOL_SOCKET
, SO_KEEPALIVE
, &on
, sizeof(on
))) {
54 PLOG(ERROR
) << "Failed to set SO_KEEPALIVE on fd: " << fd
;
57 #if defined(OS_LINUX) || defined(OS_ANDROID)
58 // Set seconds until first TCP keep alive.
59 if (setsockopt(fd
, SOL_TCP
, TCP_KEEPIDLE
, &delay
, sizeof(delay
))) {
60 PLOG(ERROR
) << "Failed to set TCP_KEEPIDLE on fd: " << fd
;
63 // Set seconds between TCP keep alives.
64 if (setsockopt(fd
, SOL_TCP
, TCP_KEEPINTVL
, &delay
, sizeof(delay
))) {
65 PLOG(ERROR
) << "Failed to set TCP_KEEPINTVL on fd: " << fd
;
72 int MapAcceptError(int os_error
) {
74 // If the client aborts the connection before the server calls accept,
75 // POSIX specifies accept should fail with ECONNABORTED. The server can
76 // ignore the error and just call accept again, so we map the error to
77 // ERR_IO_PENDING. See UNIX Network Programming, Vol. 1, 3rd Ed., Sec.
78 // 5.11, "Connection Abort before accept Returns".
80 return ERR_IO_PENDING
;
82 return MapSystemError(os_error
);
86 int MapConnectError(int os_error
) {
89 return ERR_NETWORK_ACCESS_DENIED
;
91 return ERR_CONNECTION_TIMED_OUT
;
93 int net_error
= MapSystemError(os_error
);
94 if (net_error
== ERR_FAILED
)
95 return ERR_CONNECTION_FAILED
; // More specific than ERR_FAILED.
97 // Give a more specific error when the user is offline.
98 if (net_error
== ERR_ADDRESS_UNREACHABLE
&&
99 NetworkChangeNotifier::IsOffline()) {
100 return ERR_INTERNET_DISCONNECTED
;
109 //-----------------------------------------------------------------------------
111 TCPSocketLibevent::Watcher::Watcher(
112 const base::Closure
& read_ready_callback
,
113 const base::Closure
& write_ready_callback
)
114 : read_ready_callback_(read_ready_callback
),
115 write_ready_callback_(write_ready_callback
) {
118 TCPSocketLibevent::Watcher::~Watcher() {
121 void TCPSocketLibevent::Watcher::OnFileCanReadWithoutBlocking(int /* fd */) {
122 if (!read_ready_callback_
.is_null())
123 read_ready_callback_
.Run();
128 void TCPSocketLibevent::Watcher::OnFileCanWriteWithoutBlocking(int /* fd */) {
129 if (!write_ready_callback_
.is_null())
130 write_ready_callback_
.Run();
135 TCPSocketLibevent::TCPSocketLibevent(NetLog
* net_log
,
136 const NetLog::Source
& source
)
137 : socket_(kInvalidSocket
),
138 accept_watcher_(base::Bind(&TCPSocketLibevent::DidCompleteAccept
,
139 base::Unretained(this)),
141 accept_socket_(NULL
),
142 accept_address_(NULL
),
143 read_watcher_(base::Bind(&TCPSocketLibevent::DidCompleteRead
,
144 base::Unretained(this)),
146 write_watcher_(base::Closure(),
147 base::Bind(&TCPSocketLibevent::DidCompleteConnectOrWrite
,
148 base::Unretained(this))),
151 use_tcp_fastopen_(IsTCPFastOpenEnabled()),
152 tcp_fastopen_connected_(false),
153 fast_open_status_(FAST_OPEN_STATUS_UNKNOWN
),
154 waiting_connect_(false),
155 connect_os_error_(0),
156 logging_multiple_connect_attempts_(false),
157 net_log_(BoundNetLog::Make(net_log
, NetLog::SOURCE_SOCKET
)) {
158 net_log_
.BeginEvent(NetLog::TYPE_SOCKET_ALIVE
,
159 source
.ToEventParametersCallback());
162 TCPSocketLibevent::~TCPSocketLibevent() {
163 net_log_
.EndEvent(NetLog::TYPE_SOCKET_ALIVE
);
164 if (tcp_fastopen_connected_
) {
165 UMA_HISTOGRAM_ENUMERATION("Net.TcpFastOpenSocketConnection",
166 fast_open_status_
, FAST_OPEN_MAX_VALUE
);
171 int TCPSocketLibevent::Open(AddressFamily family
) {
172 DCHECK(CalledOnValidThread());
173 DCHECK_EQ(socket_
, kInvalidSocket
);
175 socket_
= CreatePlatformSocket(ConvertAddressFamily(family
), SOCK_STREAM
,
178 PLOG(ERROR
) << "CreatePlatformSocket() returned an error";
179 return MapSystemError(errno
);
182 if (SetNonBlocking(socket_
)) {
183 int result
= MapSystemError(errno
);
191 int TCPSocketLibevent::AdoptConnectedSocket(int socket
,
192 const IPEndPoint
& peer_address
) {
193 DCHECK(CalledOnValidThread());
194 DCHECK_EQ(socket_
, kInvalidSocket
);
198 if (SetNonBlocking(socket_
)) {
199 int result
= MapSystemError(errno
);
204 peer_address_
.reset(new IPEndPoint(peer_address
));
209 int TCPSocketLibevent::Bind(const IPEndPoint
& address
) {
210 DCHECK(CalledOnValidThread());
211 DCHECK_NE(socket_
, kInvalidSocket
);
213 SockaddrStorage storage
;
214 if (!address
.ToSockAddr(storage
.addr
, &storage
.addr_len
))
215 return ERR_ADDRESS_INVALID
;
217 int result
= bind(socket_
, storage
.addr
, storage
.addr_len
);
219 PLOG(ERROR
) << "bind() returned an error";
220 return MapSystemError(errno
);
226 int TCPSocketLibevent::Listen(int backlog
) {
227 DCHECK(CalledOnValidThread());
228 DCHECK_GT(backlog
, 0);
229 DCHECK_NE(socket_
, kInvalidSocket
);
231 int result
= listen(socket_
, backlog
);
233 PLOG(ERROR
) << "listen() returned an error";
234 return MapSystemError(errno
);
240 int TCPSocketLibevent::Accept(scoped_ptr
<TCPSocketLibevent
>* socket
,
242 const CompletionCallback
& callback
) {
243 DCHECK(CalledOnValidThread());
246 DCHECK(!callback
.is_null());
247 DCHECK(accept_callback_
.is_null());
249 net_log_
.BeginEvent(NetLog::TYPE_TCP_ACCEPT
);
251 int result
= AcceptInternal(socket
, address
);
253 if (result
== ERR_IO_PENDING
) {
254 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
255 socket_
, true, base::MessageLoopForIO::WATCH_READ
,
256 &accept_socket_watcher_
, &accept_watcher_
)) {
257 PLOG(ERROR
) << "WatchFileDescriptor failed on read";
258 return MapSystemError(errno
);
261 accept_socket_
= socket
;
262 accept_address_
= address
;
263 accept_callback_
= callback
;
269 int TCPSocketLibevent::Connect(const IPEndPoint
& address
,
270 const CompletionCallback
& callback
) {
271 DCHECK(CalledOnValidThread());
272 DCHECK_NE(socket_
, kInvalidSocket
);
273 DCHECK(!waiting_connect_
);
275 // |peer_address_| will be non-NULL if Connect() has been called. Unless
276 // Close() is called to reset the internal state, a second call to Connect()
278 // Please note that we don't allow a second Connect() even if the previous
279 // Connect() has failed. Connecting the same |socket_| again after a
280 // connection attempt failed results in unspecified behavior according to
282 DCHECK(!peer_address_
);
284 if (!logging_multiple_connect_attempts_
)
285 LogConnectBegin(AddressList(address
));
287 peer_address_
.reset(new IPEndPoint(address
));
289 int rv
= DoConnect();
290 if (rv
== ERR_IO_PENDING
) {
291 // Synchronous operation not supported.
292 DCHECK(!callback
.is_null());
293 write_callback_
= callback
;
294 waiting_connect_
= true;
296 DoConnectComplete(rv
);
302 bool TCPSocketLibevent::IsConnected() const {
303 DCHECK(CalledOnValidThread());
305 if (socket_
== kInvalidSocket
|| waiting_connect_
)
308 if (use_tcp_fastopen_
&& !tcp_fastopen_connected_
&& peer_address_
) {
309 // With TCP FastOpen, we pretend that the socket is connected.
310 // This allows GetPeerAddress() to return peer_address_.
314 // Check if connection is alive.
316 int rv
= HANDLE_EINTR(recv(socket_
, &c
, 1, MSG_PEEK
));
319 if (rv
== -1 && errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
)
325 bool TCPSocketLibevent::IsConnectedAndIdle() const {
326 DCHECK(CalledOnValidThread());
328 if (socket_
== kInvalidSocket
|| waiting_connect_
)
331 // TODO(wtc): should we also handle the TCP FastOpen case here,
332 // as we do in IsConnected()?
334 // Check if connection is alive and we haven't received any data
337 int rv
= HANDLE_EINTR(recv(socket_
, &c
, 1, MSG_PEEK
));
340 if (errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
)
346 int TCPSocketLibevent::Read(IOBuffer
* buf
,
348 const CompletionCallback
& callback
) {
349 DCHECK(CalledOnValidThread());
350 DCHECK_NE(kInvalidSocket
, socket_
);
351 DCHECK(!waiting_connect_
);
352 DCHECK(read_callback_
.is_null());
353 // Synchronous operation not supported
354 DCHECK(!callback
.is_null());
355 DCHECK_GT(buf_len
, 0);
357 int nread
= HANDLE_EINTR(read(socket_
, buf
->data(), buf_len
));
359 base::StatsCounter
read_bytes("tcp.read_bytes");
360 read_bytes
.Add(nread
);
361 net_log_
.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED
, nread
,
363 RecordFastOpenStatus();
366 if (errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
) {
367 int net_error
= MapSystemError(errno
);
368 net_log_
.AddEvent(NetLog::TYPE_SOCKET_READ_ERROR
,
369 CreateNetLogSocketErrorCallback(net_error
, errno
));
373 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
374 socket_
, true, base::MessageLoopForIO::WATCH_READ
,
375 &read_socket_watcher_
, &read_watcher_
)) {
376 DVLOG(1) << "WatchFileDescriptor failed on read, errno " << errno
;
377 return MapSystemError(errno
);
381 read_buf_len_
= buf_len
;
382 read_callback_
= callback
;
383 return ERR_IO_PENDING
;
386 int TCPSocketLibevent::Write(IOBuffer
* buf
,
388 const CompletionCallback
& callback
) {
389 DCHECK(CalledOnValidThread());
390 DCHECK_NE(kInvalidSocket
, socket_
);
391 DCHECK(!waiting_connect_
);
392 DCHECK(write_callback_
.is_null());
393 // Synchronous operation not supported
394 DCHECK(!callback
.is_null());
395 DCHECK_GT(buf_len
, 0);
397 int nwrite
= InternalWrite(buf
, buf_len
);
399 base::StatsCounter
write_bytes("tcp.write_bytes");
400 write_bytes
.Add(nwrite
);
401 net_log_
.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT
, nwrite
,
405 if (errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
) {
406 int net_error
= MapSystemError(errno
);
407 net_log_
.AddEvent(NetLog::TYPE_SOCKET_WRITE_ERROR
,
408 CreateNetLogSocketErrorCallback(net_error
, errno
));
412 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
413 socket_
, true, base::MessageLoopForIO::WATCH_WRITE
,
414 &write_socket_watcher_
, &write_watcher_
)) {
415 DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno
;
416 return MapSystemError(errno
);
420 write_buf_len_
= buf_len
;
421 write_callback_
= callback
;
422 return ERR_IO_PENDING
;
425 int TCPSocketLibevent::GetLocalAddress(IPEndPoint
* address
) const {
426 DCHECK(CalledOnValidThread());
429 SockaddrStorage storage
;
430 if (getsockname(socket_
, storage
.addr
, &storage
.addr_len
) < 0)
431 return MapSystemError(errno
);
432 if (!address
->FromSockAddr(storage
.addr
, storage
.addr_len
))
433 return ERR_ADDRESS_INVALID
;
438 int TCPSocketLibevent::GetPeerAddress(IPEndPoint
* address
) const {
439 DCHECK(CalledOnValidThread());
442 return ERR_SOCKET_NOT_CONNECTED
;
443 *address
= *peer_address_
;
447 int TCPSocketLibevent::SetDefaultOptionsForServer() {
448 DCHECK(CalledOnValidThread());
449 return SetAddressReuse(true);
452 void TCPSocketLibevent::SetDefaultOptionsForClient() {
453 DCHECK(CalledOnValidThread());
455 // This mirrors the behaviour on Windows. See the comment in
456 // tcp_socket_win.cc after searching for "NODELAY".
457 SetTCPNoDelay(socket_
, true); // If SetTCPNoDelay fails, we don't care.
458 SetTCPKeepAlive(socket_
, true, kTCPKeepAliveSeconds
);
461 int TCPSocketLibevent::SetAddressReuse(bool allow
) {
462 DCHECK(CalledOnValidThread());
464 // SO_REUSEADDR is useful for server sockets to bind to a recently unbound
465 // port. When a socket is closed, the end point changes its state to TIME_WAIT
466 // and wait for 2 MSL (maximum segment lifetime) to ensure the remote peer
467 // acknowledges its closure. For server sockets, it is usually safe to
468 // bind to a TIME_WAIT end point immediately, which is a widely adopted
471 // Note that on *nix, SO_REUSEADDR does not enable the TCP socket to bind to
472 // an end point that is already bound by another socket. To do that one must
473 // set SO_REUSEPORT instead. This option is not provided on Linux prior
476 // SO_REUSEPORT is provided in MacOS X and iOS.
477 int boolean_value
= allow
? 1 : 0;
478 int rv
= setsockopt(socket_
, SOL_SOCKET
, SO_REUSEADDR
, &boolean_value
,
479 sizeof(boolean_value
));
481 return MapSystemError(errno
);
485 bool TCPSocketLibevent::SetReceiveBufferSize(int32 size
) {
486 DCHECK(CalledOnValidThread());
487 int rv
= setsockopt(socket_
, SOL_SOCKET
, SO_RCVBUF
,
488 reinterpret_cast<const char*>(&size
),
490 DCHECK(!rv
) << "Could not set socket receive buffer size: " << errno
;
494 bool TCPSocketLibevent::SetSendBufferSize(int32 size
) {
495 DCHECK(CalledOnValidThread());
496 int rv
= setsockopt(socket_
, SOL_SOCKET
, SO_SNDBUF
,
497 reinterpret_cast<const char*>(&size
),
499 DCHECK(!rv
) << "Could not set socket send buffer size: " << errno
;
503 bool TCPSocketLibevent::SetKeepAlive(bool enable
, int delay
) {
504 DCHECK(CalledOnValidThread());
505 return SetTCPKeepAlive(socket_
, enable
, delay
);
508 bool TCPSocketLibevent::SetNoDelay(bool no_delay
) {
509 DCHECK(CalledOnValidThread());
510 return SetTCPNoDelay(socket_
, no_delay
);
513 void TCPSocketLibevent::Close() {
514 DCHECK(CalledOnValidThread());
516 bool ok
= accept_socket_watcher_
.StopWatchingFileDescriptor();
518 ok
= read_socket_watcher_
.StopWatchingFileDescriptor();
520 ok
= write_socket_watcher_
.StopWatchingFileDescriptor();
523 if (socket_
!= kInvalidSocket
) {
524 if (IGNORE_EINTR(close(socket_
)) < 0)
525 PLOG(ERROR
) << "close";
526 socket_
= kInvalidSocket
;
529 if (!accept_callback_
.is_null()) {
530 accept_socket_
= NULL
;
531 accept_address_
= NULL
;
532 accept_callback_
.Reset();
535 if (!read_callback_
.is_null()) {
538 read_callback_
.Reset();
541 if (!write_callback_
.is_null()) {
544 write_callback_
.Reset();
547 tcp_fastopen_connected_
= false;
548 fast_open_status_
= FAST_OPEN_STATUS_UNKNOWN
;
549 waiting_connect_
= false;
550 peer_address_
.reset();
551 connect_os_error_
= 0;
554 bool TCPSocketLibevent::UsingTCPFastOpen() const {
555 return use_tcp_fastopen_
;
558 void TCPSocketLibevent::StartLoggingMultipleConnectAttempts(
559 const AddressList
& addresses
) {
560 if (!logging_multiple_connect_attempts_
) {
561 logging_multiple_connect_attempts_
= true;
562 LogConnectBegin(addresses
);
568 void TCPSocketLibevent::EndLoggingMultipleConnectAttempts(int net_error
) {
569 if (logging_multiple_connect_attempts_
) {
570 LogConnectEnd(net_error
);
571 logging_multiple_connect_attempts_
= false;
577 int TCPSocketLibevent::AcceptInternal(scoped_ptr
<TCPSocketLibevent
>* socket
,
578 IPEndPoint
* address
) {
579 SockaddrStorage storage
;
580 int new_socket
= HANDLE_EINTR(accept(socket_
,
583 if (new_socket
< 0) {
584 int net_error
= MapAcceptError(errno
);
585 if (net_error
!= ERR_IO_PENDING
)
586 net_log_
.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT
, net_error
);
590 IPEndPoint ip_end_point
;
591 if (!ip_end_point
.FromSockAddr(storage
.addr
, storage
.addr_len
)) {
593 if (IGNORE_EINTR(close(new_socket
)) < 0)
594 PLOG(ERROR
) << "close";
595 net_log_
.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT
,
596 ERR_ADDRESS_INVALID
);
597 return ERR_ADDRESS_INVALID
;
599 scoped_ptr
<TCPSocketLibevent
> tcp_socket(new TCPSocketLibevent(
600 net_log_
.net_log(), net_log_
.source()));
601 int adopt_result
= tcp_socket
->AdoptConnectedSocket(new_socket
, ip_end_point
);
602 if (adopt_result
!= OK
) {
603 net_log_
.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT
, adopt_result
);
606 *socket
= tcp_socket
.Pass();
607 *address
= ip_end_point
;
608 net_log_
.EndEvent(NetLog::TYPE_TCP_ACCEPT
,
609 CreateNetLogIPEndPointCallback(&ip_end_point
));
613 int TCPSocketLibevent::DoConnect() {
614 DCHECK_EQ(0, connect_os_error_
);
616 net_log_
.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT
,
617 CreateNetLogIPEndPointCallback(peer_address_
.get()));
619 // Connect the socket.
620 if (!use_tcp_fastopen_
) {
621 SockaddrStorage storage
;
622 if (!peer_address_
->ToSockAddr(storage
.addr
, &storage
.addr_len
))
623 return ERR_INVALID_ARGUMENT
;
625 if (!HANDLE_EINTR(connect(socket_
, storage
.addr
, storage
.addr_len
))) {
626 // Connected without waiting!
630 // With TCP FastOpen, we pretend that the socket is connected.
631 DCHECK(!tcp_fastopen_connected_
);
635 // Check if the connect() failed synchronously.
636 connect_os_error_
= errno
;
637 if (connect_os_error_
!= EINPROGRESS
)
638 return MapConnectError(connect_os_error_
);
640 // Otherwise the connect() is going to complete asynchronously, so watch
641 // for its completion.
642 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
643 socket_
, true, base::MessageLoopForIO::WATCH_WRITE
,
644 &write_socket_watcher_
, &write_watcher_
)) {
645 connect_os_error_
= errno
;
646 DVLOG(1) << "WatchFileDescriptor failed: " << connect_os_error_
;
647 return MapSystemError(connect_os_error_
);
650 return ERR_IO_PENDING
;
653 void TCPSocketLibevent::DoConnectComplete(int result
) {
654 // Log the end of this attempt (and any OS error it threw).
655 int os_error
= connect_os_error_
;
656 connect_os_error_
= 0;
658 net_log_
.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT
,
659 NetLog::IntegerCallback("os_error", os_error
));
661 net_log_
.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT
);
664 if (!logging_multiple_connect_attempts_
)
665 LogConnectEnd(result
);
668 void TCPSocketLibevent::LogConnectBegin(const AddressList
& addresses
) {
669 base::StatsCounter
connects("tcp.connect");
670 connects
.Increment();
672 net_log_
.BeginEvent(NetLog::TYPE_TCP_CONNECT
,
673 addresses
.CreateNetLogCallback());
676 void TCPSocketLibevent::LogConnectEnd(int net_error
) {
678 UpdateConnectionTypeHistograms(CONNECTION_ANY
);
680 if (net_error
!= OK
) {
681 net_log_
.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT
, net_error
);
685 SockaddrStorage storage
;
686 int rv
= getsockname(socket_
, storage
.addr
, &storage
.addr_len
);
688 PLOG(ERROR
) << "getsockname() [rv: " << rv
<< "] error: ";
690 net_log_
.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT
, rv
);
694 net_log_
.EndEvent(NetLog::TYPE_TCP_CONNECT
,
695 CreateNetLogSourceAddressCallback(storage
.addr
,
699 void TCPSocketLibevent::DidCompleteRead() {
700 RecordFastOpenStatus();
701 if (read_callback_
.is_null())
704 int bytes_transferred
;
705 bytes_transferred
= HANDLE_EINTR(read(socket_
, read_buf_
->data(),
709 if (bytes_transferred
>= 0) {
710 result
= bytes_transferred
;
711 base::StatsCounter
read_bytes("tcp.read_bytes");
712 read_bytes
.Add(bytes_transferred
);
713 net_log_
.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED
, result
,
716 result
= MapSystemError(errno
);
717 if (result
!= ERR_IO_PENDING
) {
718 net_log_
.AddEvent(NetLog::TYPE_SOCKET_READ_ERROR
,
719 CreateNetLogSocketErrorCallback(result
, errno
));
723 if (result
!= ERR_IO_PENDING
) {
726 bool ok
= read_socket_watcher_
.StopWatchingFileDescriptor();
728 base::ResetAndReturn(&read_callback_
).Run(result
);
732 void TCPSocketLibevent::DidCompleteWrite() {
733 if (write_callback_
.is_null())
736 int bytes_transferred
;
737 bytes_transferred
= HANDLE_EINTR(write(socket_
, write_buf_
->data(),
741 if (bytes_transferred
>= 0) {
742 result
= bytes_transferred
;
743 base::StatsCounter
write_bytes("tcp.write_bytes");
744 write_bytes
.Add(bytes_transferred
);
745 net_log_
.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT
, result
,
748 result
= MapSystemError(errno
);
749 if (result
!= ERR_IO_PENDING
) {
750 net_log_
.AddEvent(NetLog::TYPE_SOCKET_WRITE_ERROR
,
751 CreateNetLogSocketErrorCallback(result
, errno
));
755 if (result
!= ERR_IO_PENDING
) {
758 write_socket_watcher_
.StopWatchingFileDescriptor();
759 base::ResetAndReturn(&write_callback_
).Run(result
);
763 void TCPSocketLibevent::DidCompleteConnect() {
764 DCHECK(waiting_connect_
);
766 // Get the error that connect() completed with.
768 socklen_t len
= sizeof(os_error
);
769 if (getsockopt(socket_
, SOL_SOCKET
, SO_ERROR
, &os_error
, &len
) < 0)
772 int result
= MapConnectError(os_error
);
773 connect_os_error_
= os_error
;
774 if (result
!= ERR_IO_PENDING
) {
775 DoConnectComplete(result
);
776 waiting_connect_
= false;
777 write_socket_watcher_
.StopWatchingFileDescriptor();
778 base::ResetAndReturn(&write_callback_
).Run(result
);
782 void TCPSocketLibevent::DidCompleteConnectOrWrite() {
783 if (waiting_connect_
)
784 DidCompleteConnect();
789 void TCPSocketLibevent::DidCompleteAccept() {
790 DCHECK(CalledOnValidThread());
792 int result
= AcceptInternal(accept_socket_
, accept_address_
);
793 if (result
!= ERR_IO_PENDING
) {
794 accept_socket_
= NULL
;
795 accept_address_
= NULL
;
796 bool ok
= accept_socket_watcher_
.StopWatchingFileDescriptor();
798 CompletionCallback callback
= accept_callback_
;
799 accept_callback_
.Reset();
800 callback
.Run(result
);
804 int TCPSocketLibevent::InternalWrite(IOBuffer
* buf
, int buf_len
) {
806 if (use_tcp_fastopen_
&& !tcp_fastopen_connected_
) {
807 SockaddrStorage storage
;
808 if (!peer_address_
->ToSockAddr(storage
.addr
, &storage
.addr_len
)) {
813 int flags
= 0x20000000; // Magic flag to enable TCP_FASTOPEN.
814 #if defined(OS_LINUX)
815 // sendto() will fail with EPIPE when the system doesn't support TCP Fast
816 // Open. Theoretically that shouldn't happen since the caller should check
817 // for system support on startup, but users may dynamically disable TCP Fast
819 flags
|= MSG_NOSIGNAL
;
820 #endif // defined(OS_LINUX)
821 nwrite
= HANDLE_EINTR(sendto(socket_
,
827 tcp_fastopen_connected_
= true;
830 DCHECK_NE(EPIPE
, errno
);
832 // If errno == EINPROGRESS, that means the kernel didn't have a cookie
833 // and would block. The kernel is internally doing a connect() though.
834 // Remap EINPROGRESS to EAGAIN so we treat this the same as our other
835 // asynchronous cases. Note that the user buffer has not been copied to
837 if (errno
== EINPROGRESS
) {
839 fast_open_status_
= FAST_OPEN_SLOW_CONNECT_RETURN
;
841 fast_open_status_
= FAST_OPEN_ERROR
;
844 fast_open_status_
= FAST_OPEN_FAST_CONNECT_RETURN
;
847 nwrite
= HANDLE_EINTR(write(socket_
, buf
->data(), buf_len
));
852 void TCPSocketLibevent::RecordFastOpenStatus() {
853 if (use_tcp_fastopen_
&&
854 (fast_open_status_
== FAST_OPEN_FAST_CONNECT_RETURN
||
855 fast_open_status_
== FAST_OPEN_SLOW_CONNECT_RETURN
)) {
856 DCHECK_NE(FAST_OPEN_STATUS_UNKNOWN
, fast_open_status_
);
857 bool getsockopt_success(false);
858 bool server_acked_data(false);
859 #if defined(TCP_INFO)
860 // Probe to see the if the socket used TCP Fast Open.
862 socklen_t info_len
= sizeof(tcp_info
);
864 getsockopt(socket_
, IPPROTO_TCP
, TCP_INFO
, &info
, &info_len
) == 0 &&
865 info_len
== sizeof(tcp_info
);
866 server_acked_data
= getsockopt_success
&&
867 (info
.tcpi_options
& TCPI_OPT_SYN_DATA
);
869 if (getsockopt_success
) {
870 if (fast_open_status_
== FAST_OPEN_FAST_CONNECT_RETURN
) {
871 fast_open_status_
= (server_acked_data
? FAST_OPEN_SYN_DATA_ACK
:
872 FAST_OPEN_SYN_DATA_NACK
);
874 fast_open_status_
= (server_acked_data
? FAST_OPEN_NO_SYN_DATA_ACK
:
875 FAST_OPEN_NO_SYN_DATA_NACK
);
878 fast_open_status_
= (fast_open_status_
== FAST_OPEN_FAST_CONNECT_RETURN
?
879 FAST_OPEN_SYN_DATA_FAILED
:
880 FAST_OPEN_NO_SYN_DATA_FAILED
);