1 // Copyright (c) 2012 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_client_socket.h"
10 #include <sys/socket.h>
11 #include <netinet/tcp.h>
13 #include <netinet/in.h>
16 #include "base/logging.h"
17 #include "base/message_loop.h"
18 #include "base/metrics/histogram.h"
19 #include "base/metrics/stats_counters.h"
20 #include "base/posix/eintr_wrapper.h"
21 #include "base/string_util.h"
22 #include "net/base/connection_type_histograms.h"
23 #include "net/base/io_buffer.h"
24 #include "net/base/ip_endpoint.h"
25 #include "net/base/net_errors.h"
26 #include "net/base/net_log.h"
27 #include "net/base/net_util.h"
28 #include "net/base/network_change_notifier.h"
29 #include "net/socket/socket_net_log_params.h"
31 // If we don't have a definition for TCPI_OPT_SYN_DATA, create one.
32 #ifndef TCPI_OPT_SYN_DATA
33 #define TCPI_OPT_SYN_DATA 32
40 const int kInvalidSocket
= -1;
41 const int kTCPKeepAliveSeconds
= 45;
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
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
,
54 // SetTCPKeepAlive sets SO_KEEPALIVE.
55 bool SetTCPKeepAlive(int fd
, bool enable
, int delay
) {
56 int on
= enable
? 1 : 0;
57 if (setsockopt(fd
, SOL_SOCKET
, SO_KEEPALIVE
, &on
, sizeof(on
))) {
58 PLOG(ERROR
) << "Failed to set SO_KEEPALIVE on fd: " << fd
;
61 #if defined(OS_LINUX) || defined(OS_ANDROID)
62 // Set seconds until first TCP keep alive.
63 if (setsockopt(fd
, SOL_TCP
, TCP_KEEPIDLE
, &delay
, sizeof(delay
))) {
64 PLOG(ERROR
) << "Failed to set TCP_KEEPIDLE on fd: " << fd
;
67 // Set seconds between TCP keep alives.
68 if (setsockopt(fd
, SOL_TCP
, TCP_KEEPINTVL
, &delay
, sizeof(delay
))) {
69 PLOG(ERROR
) << "Failed to set TCP_KEEPINTVL on fd: " << fd
;
76 // Sets socket parameters. Returns the OS error code (or 0 on
78 int SetupSocket(int socket
) {
79 if (SetNonBlocking(socket
))
82 // This mirrors the behaviour on Windows. See the comment in
83 // tcp_client_socket_win.cc after searching for "NODELAY".
84 SetTCPNoDelay(socket
, true); // If SetTCPNoDelay fails, we don't care.
85 SetTCPKeepAlive(socket
, true, kTCPKeepAliveSeconds
);
90 // Creates a new socket and sets default parameters for it. Returns
91 // the OS error code (or 0 on success).
92 int CreateSocket(int family
, int* socket
) {
93 *socket
= ::socket(family
, SOCK_STREAM
, IPPROTO_TCP
);
94 if (*socket
== kInvalidSocket
)
96 int error
= SetupSocket(*socket
);
98 if (HANDLE_EINTR(close(*socket
)) < 0)
99 PLOG(ERROR
) << "close";
100 *socket
= kInvalidSocket
;
106 int MapConnectError(int os_error
) {
109 return ERR_NETWORK_ACCESS_DENIED
;
111 return ERR_CONNECTION_TIMED_OUT
;
113 int net_error
= MapSystemError(os_error
);
114 if (net_error
== ERR_FAILED
)
115 return ERR_CONNECTION_FAILED
; // More specific than ERR_FAILED.
117 // Give a more specific error when the user is offline.
118 if (net_error
== ERR_ADDRESS_UNREACHABLE
&&
119 NetworkChangeNotifier::IsOffline()) {
120 return ERR_INTERNET_DISCONNECTED
;
129 //-----------------------------------------------------------------------------
131 TCPClientSocketLibevent::TCPClientSocketLibevent(
132 const AddressList
& addresses
,
133 net::NetLog
* net_log
,
134 const net::NetLog::Source
& source
)
135 : socket_(kInvalidSocket
),
136 bound_socket_(kInvalidSocket
),
137 addresses_(addresses
),
138 current_address_index_(-1),
140 write_watcher_(this),
141 next_connect_state_(CONNECT_STATE_NONE
),
142 connect_os_error_(0),
143 net_log_(BoundNetLog::Make(net_log
, NetLog::SOURCE_SOCKET
)),
144 previously_disconnected_(false),
145 use_tcp_fastopen_(IsTCPFastOpenEnabled()),
146 tcp_fastopen_connected_(false),
147 fast_open_status_(FAST_OPEN_STATUS_UNKNOWN
) {
148 net_log_
.BeginEvent(NetLog::TYPE_SOCKET_ALIVE
,
149 source
.ToEventParametersCallback());
152 TCPClientSocketLibevent::~TCPClientSocketLibevent() {
154 net_log_
.EndEvent(NetLog::TYPE_SOCKET_ALIVE
);
155 if (tcp_fastopen_connected_
) {
156 UMA_HISTOGRAM_ENUMERATION("Net.TcpFastOpenSocketConnection",
157 fast_open_status_
, FAST_OPEN_MAX_VALUE
);
161 int TCPClientSocketLibevent::AdoptSocket(int socket
) {
162 DCHECK_EQ(socket_
, kInvalidSocket
);
164 int error
= SetupSocket(socket
);
166 return MapSystemError(error
);
170 // This is to make GetPeerAddress() work. It's up to the caller ensure
171 // that |address_| contains a reasonable address for this
172 // socket. (i.e. at least match IPv4 vs IPv6!).
173 current_address_index_
= 0;
174 use_history_
.set_was_ever_connected();
179 int TCPClientSocketLibevent::Bind(const IPEndPoint
& address
) {
180 if (current_address_index_
>= 0 || bind_address_
.get()) {
181 // Cannot bind the socket if we are already bound connected or
183 return ERR_UNEXPECTED
;
186 SockaddrStorage storage
;
187 if (!address
.ToSockAddr(storage
.addr
, &storage
.addr_len
))
188 return ERR_INVALID_ARGUMENT
;
190 // Create |bound_socket_| and try to bind it to |address|.
191 int error
= CreateSocket(address
.GetSockAddrFamily(), &bound_socket_
);
193 return MapSystemError(error
);
195 if (HANDLE_EINTR(bind(bound_socket_
, storage
.addr
, storage
.addr_len
))) {
197 if (HANDLE_EINTR(close(bound_socket_
)) < 0)
198 PLOG(ERROR
) << "close";
199 bound_socket_
= kInvalidSocket
;
200 return MapSystemError(error
);
203 bind_address_
.reset(new IPEndPoint(address
));
208 int TCPClientSocketLibevent::Connect(const CompletionCallback
& callback
) {
209 DCHECK(CalledOnValidThread());
211 // If already connected, then just return OK.
212 if (socket_
!= kInvalidSocket
)
215 base::StatsCounter
connects("tcp.connect");
216 connects
.Increment();
218 DCHECK(!waiting_connect());
220 net_log_
.BeginEvent(NetLog::TYPE_TCP_CONNECT
,
221 addresses_
.CreateNetLogCallback());
223 // We will try to connect to each address in addresses_. Start with the
224 // first one in the list.
225 next_connect_state_
= CONNECT_STATE_CONNECT
;
226 current_address_index_
= 0;
228 int rv
= DoConnectLoop(OK
);
229 if (rv
== ERR_IO_PENDING
) {
230 // Synchronous operation not supported.
231 DCHECK(!callback
.is_null());
232 write_callback_
= callback
;
234 LogConnectCompletion(rv
);
240 int TCPClientSocketLibevent::DoConnectLoop(int result
) {
241 DCHECK_NE(next_connect_state_
, CONNECT_STATE_NONE
);
245 ConnectState state
= next_connect_state_
;
246 next_connect_state_
= CONNECT_STATE_NONE
;
248 case CONNECT_STATE_CONNECT
:
252 case CONNECT_STATE_CONNECT_COMPLETE
:
253 rv
= DoConnectComplete(rv
);
256 LOG(DFATAL
) << "bad state";
260 } while (rv
!= ERR_IO_PENDING
&& next_connect_state_
!= CONNECT_STATE_NONE
);
265 int TCPClientSocketLibevent::DoConnect() {
266 DCHECK_GE(current_address_index_
, 0);
267 DCHECK_LT(current_address_index_
, static_cast<int>(addresses_
.size()));
268 DCHECK_EQ(0, connect_os_error_
);
270 const IPEndPoint
& endpoint
= addresses_
[current_address_index_
];
272 if (previously_disconnected_
) {
273 use_history_
.Reset();
274 previously_disconnected_
= false;
277 net_log_
.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT
,
278 CreateNetLogIPEndPointCallback(&endpoint
));
280 next_connect_state_
= CONNECT_STATE_CONNECT_COMPLETE
;
282 if (bound_socket_
!= kInvalidSocket
) {
283 DCHECK(bind_address_
.get());
284 socket_
= bound_socket_
;
285 bound_socket_
= kInvalidSocket
;
287 // Create a non-blocking socket.
288 connect_os_error_
= CreateSocket(endpoint
.GetSockAddrFamily(), &socket_
);
289 if (connect_os_error_
)
290 return MapSystemError(connect_os_error_
);
292 if (bind_address_
.get()) {
293 SockaddrStorage storage
;
294 if (!bind_address_
->ToSockAddr(storage
.addr
, &storage
.addr_len
))
295 return ERR_INVALID_ARGUMENT
;
296 if (HANDLE_EINTR(bind(socket_
, storage
.addr
, storage
.addr_len
)))
297 return MapSystemError(errno
);
301 // Connect the socket.
302 if (!use_tcp_fastopen_
) {
303 SockaddrStorage storage
;
304 if (!endpoint
.ToSockAddr(storage
.addr
, &storage
.addr_len
))
305 return ERR_INVALID_ARGUMENT
;
307 if (!HANDLE_EINTR(connect(socket_
, storage
.addr
, storage
.addr_len
))) {
308 // Connected without waiting!
312 // With TCP FastOpen, we pretend that the socket is connected.
313 DCHECK(!tcp_fastopen_connected_
);
317 // Check if the connect() failed synchronously.
318 connect_os_error_
= errno
;
319 if (connect_os_error_
!= EINPROGRESS
)
320 return MapConnectError(connect_os_error_
);
322 // Otherwise the connect() is going to complete asynchronously, so watch
323 // for its completion.
324 if (!MessageLoopForIO::current()->WatchFileDescriptor(
325 socket_
, true, MessageLoopForIO::WATCH_WRITE
, &write_socket_watcher_
,
327 connect_os_error_
= errno
;
328 DVLOG(1) << "WatchFileDescriptor failed: " << connect_os_error_
;
329 return MapSystemError(connect_os_error_
);
332 return ERR_IO_PENDING
;
335 int TCPClientSocketLibevent::DoConnectComplete(int result
) {
336 // Log the end of this attempt (and any OS error it threw).
337 int os_error
= connect_os_error_
;
338 connect_os_error_
= 0;
340 net_log_
.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT
,
341 NetLog::IntegerCallback("os_error", os_error
));
343 net_log_
.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT
);
347 write_socket_watcher_
.StopWatchingFileDescriptor();
348 use_history_
.set_was_ever_connected();
352 // Close whatever partially connected socket we currently have.
355 // Try to fall back to the next address in the list.
356 if (current_address_index_
+ 1 < static_cast<int>(addresses_
.size())) {
357 next_connect_state_
= CONNECT_STATE_CONNECT
;
358 ++current_address_index_
;
362 // Otherwise there is nothing to fall back to, so give up.
366 void TCPClientSocketLibevent::Disconnect() {
367 DCHECK(CalledOnValidThread());
370 current_address_index_
= -1;
371 bind_address_
.reset();
374 void TCPClientSocketLibevent::DoDisconnect() {
375 if (socket_
== kInvalidSocket
)
378 bool ok
= read_socket_watcher_
.StopWatchingFileDescriptor();
380 ok
= write_socket_watcher_
.StopWatchingFileDescriptor();
382 if (HANDLE_EINTR(close(socket_
)) < 0)
383 PLOG(ERROR
) << "close";
384 socket_
= kInvalidSocket
;
385 previously_disconnected_
= true;
388 bool TCPClientSocketLibevent::IsConnected() const {
389 DCHECK(CalledOnValidThread());
391 if (socket_
== kInvalidSocket
|| waiting_connect())
394 if (use_tcp_fastopen_
&& !tcp_fastopen_connected_
) {
395 // With TCP FastOpen, we pretend that the socket is connected.
396 // This allows GetPeerAddress() to return current_ai_ as the peer
397 // address. Since we don't fail over to the next address if
398 // sendto() fails, current_ai_ is the only possible peer address.
399 CHECK_LT(current_address_index_
, static_cast<int>(addresses_
.size()));
403 // Check if connection is alive.
405 int rv
= HANDLE_EINTR(recv(socket_
, &c
, 1, MSG_PEEK
));
408 if (rv
== -1 && errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
)
414 bool TCPClientSocketLibevent::IsConnectedAndIdle() const {
415 DCHECK(CalledOnValidThread());
417 if (socket_
== kInvalidSocket
|| waiting_connect())
420 // TODO(wtc): should we also handle the TCP FastOpen case here,
421 // as we do in IsConnected()?
423 // Check if connection is alive and we haven't received any data
426 int rv
= HANDLE_EINTR(recv(socket_
, &c
, 1, MSG_PEEK
));
429 if (errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
)
435 int TCPClientSocketLibevent::Read(IOBuffer
* buf
,
437 const CompletionCallback
& callback
) {
438 DCHECK(CalledOnValidThread());
439 DCHECK_NE(kInvalidSocket
, socket_
);
440 DCHECK(!waiting_connect());
441 DCHECK(read_callback_
.is_null());
442 // Synchronous operation not supported
443 DCHECK(!callback
.is_null());
444 DCHECK_GT(buf_len
, 0);
446 if (use_tcp_fastopen_
&&
447 (fast_open_status_
== FAST_OPEN_FAST_CONNECT_RETURN
||
448 fast_open_status_
== FAST_OPEN_SLOW_CONNECT_RETURN
)) {
449 DCHECK_NE(FAST_OPEN_STATUS_UNKNOWN
, fast_open_status_
);
450 bool getsockopt_success(false);
451 bool server_acked_data(false);
452 #if defined(TCP_INFO)
453 // Probe to see the if the socket used TCP Fast Open.
455 socklen_t info_len
= sizeof(tcp_info
);
457 getsockopt(socket_
, IPPROTO_TCP
, TCP_INFO
, &info
, &info_len
) == 0 &&
458 info_len
== sizeof(tcp_info
);
459 server_acked_data
= getsockopt_success
&&
460 (info
.tcpi_options
& TCPI_OPT_SYN_DATA
);
462 if (getsockopt_success
) {
463 if (fast_open_status_
== FAST_OPEN_FAST_CONNECT_RETURN
) {
464 fast_open_status_
= (server_acked_data
? FAST_OPEN_SYN_DATA_ACK
:
465 FAST_OPEN_SYN_DATA_NACK
);
467 fast_open_status_
= (server_acked_data
? FAST_OPEN_NO_SYN_DATA_ACK
:
468 FAST_OPEN_NO_SYN_DATA_NACK
);
471 fast_open_status_
= (fast_open_status_
== FAST_OPEN_FAST_CONNECT_RETURN
?
472 FAST_OPEN_SYN_DATA_FAILED
:
473 FAST_OPEN_NO_SYN_DATA_FAILED
);
477 int nread
= HANDLE_EINTR(read(socket_
, buf
->data(), buf_len
));
479 base::StatsCounter
read_bytes("tcp.read_bytes");
480 read_bytes
.Add(nread
);
482 use_history_
.set_was_used_to_convey_data();
483 net_log_
.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED
, nread
,
487 if (errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
) {
488 int net_error
= MapSystemError(errno
);
489 net_log_
.AddEvent(NetLog::TYPE_SOCKET_READ_ERROR
,
490 CreateNetLogSocketErrorCallback(net_error
, errno
));
494 if (!MessageLoopForIO::current()->WatchFileDescriptor(
495 socket_
, true, MessageLoopForIO::WATCH_READ
,
496 &read_socket_watcher_
, &read_watcher_
)) {
497 DVLOG(1) << "WatchFileDescriptor failed on read, errno " << errno
;
498 return MapSystemError(errno
);
502 read_buf_len_
= buf_len
;
503 read_callback_
= callback
;
504 return ERR_IO_PENDING
;
507 int TCPClientSocketLibevent::Write(IOBuffer
* buf
,
509 const CompletionCallback
& callback
) {
510 DCHECK(CalledOnValidThread());
511 DCHECK_NE(kInvalidSocket
, socket_
);
512 DCHECK(!waiting_connect());
513 DCHECK(write_callback_
.is_null());
514 // Synchronous operation not supported
515 DCHECK(!callback
.is_null());
516 DCHECK_GT(buf_len
, 0);
518 int nwrite
= InternalWrite(buf
, buf_len
);
520 base::StatsCounter
write_bytes("tcp.write_bytes");
521 write_bytes
.Add(nwrite
);
523 use_history_
.set_was_used_to_convey_data();
524 net_log_
.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT
, nwrite
,
528 if (errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
) {
529 int net_error
= MapSystemError(errno
);
530 net_log_
.AddEvent(NetLog::TYPE_SOCKET_WRITE_ERROR
,
531 CreateNetLogSocketErrorCallback(net_error
, errno
));
535 if (!MessageLoopForIO::current()->WatchFileDescriptor(
536 socket_
, true, MessageLoopForIO::WATCH_WRITE
,
537 &write_socket_watcher_
, &write_watcher_
)) {
538 DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno
;
539 return MapSystemError(errno
);
543 write_buf_len_
= buf_len
;
544 write_callback_
= callback
;
545 return ERR_IO_PENDING
;
548 int TCPClientSocketLibevent::InternalWrite(IOBuffer
* buf
, int buf_len
) {
550 if (use_tcp_fastopen_
&& !tcp_fastopen_connected_
) {
551 SockaddrStorage storage
;
552 if (!addresses_
[current_address_index_
].ToSockAddr(storage
.addr
,
553 &storage
.addr_len
)) {
558 int flags
= 0x20000000; // Magic flag to enable TCP_FASTOPEN.
559 #if defined(OS_LINUX)
560 // sendto() will fail with EPIPE when the system doesn't support TCP Fast
561 // Open. Theoretically that shouldn't happen since the caller should check
562 // for system support on startup, but users may dynamically disable TCP Fast
564 flags
|= MSG_NOSIGNAL
;
565 #endif // defined(OS_LINUX)
566 nwrite
= HANDLE_EINTR(sendto(socket_
,
572 tcp_fastopen_connected_
= true;
575 DCHECK_NE(EPIPE
, errno
);
577 // If errno == EINPROGRESS, that means the kernel didn't have a cookie
578 // and would block. The kernel is internally doing a connect() though.
579 // Remap EINPROGRESS to EAGAIN so we treat this the same as our other
580 // asynchronous cases. Note that the user buffer has not been copied to
582 if (errno
== EINPROGRESS
) {
584 fast_open_status_
= FAST_OPEN_SLOW_CONNECT_RETURN
;
586 fast_open_status_
= FAST_OPEN_ERROR
;
589 fast_open_status_
= FAST_OPEN_FAST_CONNECT_RETURN
;
592 nwrite
= HANDLE_EINTR(write(socket_
, buf
->data(), buf_len
));
597 bool TCPClientSocketLibevent::SetReceiveBufferSize(int32 size
) {
598 DCHECK(CalledOnValidThread());
599 int rv
= setsockopt(socket_
, SOL_SOCKET
, SO_RCVBUF
,
600 reinterpret_cast<const char*>(&size
),
602 DCHECK(!rv
) << "Could not set socket receive buffer size: " << errno
;
606 bool TCPClientSocketLibevent::SetSendBufferSize(int32 size
) {
607 DCHECK(CalledOnValidThread());
608 int rv
= setsockopt(socket_
, SOL_SOCKET
, SO_SNDBUF
,
609 reinterpret_cast<const char*>(&size
),
611 DCHECK(!rv
) << "Could not set socket send buffer size: " << errno
;
615 bool TCPClientSocketLibevent::SetKeepAlive(bool enable
, int delay
) {
616 int socket
= socket_
!= kInvalidSocket
? socket_
: bound_socket_
;
617 return SetTCPKeepAlive(socket
, enable
, delay
);
620 bool TCPClientSocketLibevent::SetNoDelay(bool no_delay
) {
621 int socket
= socket_
!= kInvalidSocket
? socket_
: bound_socket_
;
622 return SetTCPNoDelay(socket
, no_delay
);
625 void TCPClientSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
626 if (!socket_
->read_callback_
.is_null())
627 socket_
->DidCompleteRead();
630 void TCPClientSocketLibevent::WriteWatcher::OnFileCanWriteWithoutBlocking(int) {
631 if (socket_
->waiting_connect()) {
632 socket_
->DidCompleteConnect();
633 } else if (!socket_
->write_callback_
.is_null()) {
634 socket_
->DidCompleteWrite();
638 void TCPClientSocketLibevent::LogConnectCompletion(int net_error
) {
640 UpdateConnectionTypeHistograms(CONNECTION_ANY
);
642 if (net_error
!= OK
) {
643 net_log_
.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT
, net_error
);
647 SockaddrStorage storage
;
648 int rv
= getsockname(socket_
, storage
.addr
, &storage
.addr_len
);
650 PLOG(ERROR
) << "getsockname() [rv: " << rv
<< "] error: ";
652 net_log_
.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT
, rv
);
656 net_log_
.EndEvent(NetLog::TYPE_TCP_CONNECT
,
657 CreateNetLogSourceAddressCallback(storage
.addr
,
661 void TCPClientSocketLibevent::DoReadCallback(int rv
) {
662 DCHECK_NE(rv
, ERR_IO_PENDING
);
663 DCHECK(!read_callback_
.is_null());
665 // since Run may result in Read being called, clear read_callback_ up front.
666 CompletionCallback c
= read_callback_
;
667 read_callback_
.Reset();
671 void TCPClientSocketLibevent::DoWriteCallback(int rv
) {
672 DCHECK_NE(rv
, ERR_IO_PENDING
);
673 DCHECK(!write_callback_
.is_null());
675 // since Run may result in Write being called, clear write_callback_ up front.
676 CompletionCallback c
= write_callback_
;
677 write_callback_
.Reset();
681 void TCPClientSocketLibevent::DidCompleteConnect() {
682 DCHECK_EQ(next_connect_state_
, CONNECT_STATE_CONNECT_COMPLETE
);
684 // Get the error that connect() completed with.
686 socklen_t len
= sizeof(os_error
);
687 if (getsockopt(socket_
, SOL_SOCKET
, SO_ERROR
, &os_error
, &len
) < 0)
690 // TODO(eroman): Is this check really necessary?
691 if (os_error
== EINPROGRESS
|| os_error
== EALREADY
) {
692 NOTREACHED(); // This indicates a bug in libevent or our code.
696 connect_os_error_
= os_error
;
697 int rv
= DoConnectLoop(MapConnectError(os_error
));
698 if (rv
!= ERR_IO_PENDING
) {
699 LogConnectCompletion(rv
);
704 void TCPClientSocketLibevent::DidCompleteRead() {
705 int bytes_transferred
;
706 bytes_transferred
= HANDLE_EINTR(read(socket_
, read_buf_
->data(),
710 if (bytes_transferred
>= 0) {
711 result
= bytes_transferred
;
712 base::StatsCounter
read_bytes("tcp.read_bytes");
713 read_bytes
.Add(bytes_transferred
);
714 if (bytes_transferred
> 0)
715 use_history_
.set_was_used_to_convey_data();
716 net_log_
.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED
, result
,
719 result
= MapSystemError(errno
);
720 if (result
!= ERR_IO_PENDING
) {
721 net_log_
.AddEvent(NetLog::TYPE_SOCKET_READ_ERROR
,
722 CreateNetLogSocketErrorCallback(result
, errno
));
726 if (result
!= ERR_IO_PENDING
) {
729 bool ok
= read_socket_watcher_
.StopWatchingFileDescriptor();
731 DoReadCallback(result
);
735 void TCPClientSocketLibevent::DidCompleteWrite() {
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 if (bytes_transferred
> 0)
746 use_history_
.set_was_used_to_convey_data();
747 net_log_
.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT
, result
,
750 result
= MapSystemError(errno
);
751 if (result
!= ERR_IO_PENDING
) {
752 net_log_
.AddEvent(NetLog::TYPE_SOCKET_WRITE_ERROR
,
753 CreateNetLogSocketErrorCallback(result
, errno
));
757 if (result
!= ERR_IO_PENDING
) {
760 write_socket_watcher_
.StopWatchingFileDescriptor();
761 DoWriteCallback(result
);
765 int TCPClientSocketLibevent::GetPeerAddress(IPEndPoint
* address
) const {
766 DCHECK(CalledOnValidThread());
769 return ERR_SOCKET_NOT_CONNECTED
;
770 *address
= addresses_
[current_address_index_
];
774 int TCPClientSocketLibevent::GetLocalAddress(IPEndPoint
* address
) const {
775 DCHECK(CalledOnValidThread());
777 if (socket_
== kInvalidSocket
) {
778 if (bind_address_
.get()) {
779 *address
= *bind_address_
;
782 return ERR_SOCKET_NOT_CONNECTED
;
785 SockaddrStorage storage
;
786 if (getsockname(socket_
, storage
.addr
, &storage
.addr_len
))
787 return MapSystemError(errno
);
788 if (!address
->FromSockAddr(storage
.addr
, storage
.addr_len
))
794 const BoundNetLog
& TCPClientSocketLibevent::NetLog() const {
798 void TCPClientSocketLibevent::SetSubresourceSpeculation() {
799 use_history_
.set_subresource_speculation();
802 void TCPClientSocketLibevent::SetOmniboxSpeculation() {
803 use_history_
.set_omnibox_speculation();
806 bool TCPClientSocketLibevent::WasEverUsed() const {
807 return use_history_
.was_used_to_convey_data();
810 bool TCPClientSocketLibevent::UsingTCPFastOpen() const {
811 return use_tcp_fastopen_
;
814 bool TCPClientSocketLibevent::WasNpnNegotiated() const {
818 NextProto
TCPClientSocketLibevent::GetNegotiatedProtocol() const {
819 return kProtoUnknown
;
822 bool TCPClientSocketLibevent::GetSSLInfo(SSLInfo
* ssl_info
) {