Ignore non-active fullscreen windows for shelf state.
[chromium-blink-merge.git] / net / socket / tcp_socket_libevent.cc
blobf4e4fe861afe4759a9d355cfcd19840d9eaf73cd
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"
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <netdb.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
32 #endif
34 namespace net {
36 namespace {
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
43 // `man 7 tcp`.
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));
47 return error == 0;
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;
55 return false;
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;
61 return false;
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;
66 return false;
68 #endif
69 return true;
72 int MapAcceptError(int os_error) {
73 switch (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".
79 case ECONNABORTED:
80 return ERR_IO_PENDING;
81 default:
82 return MapSystemError(os_error);
86 int MapConnectError(int os_error) {
87 switch (os_error) {
88 case EACCES:
89 return ERR_NETWORK_ACCESS_DENIED;
90 case ETIMEDOUT:
91 return ERR_CONNECTION_TIMED_OUT;
92 default: {
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;
102 return net_error;
107 } // namespace
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();
124 else
125 NOTREACHED();
128 void TCPSocketLibevent::Watcher::OnFileCanWriteWithoutBlocking(int /* fd */) {
129 if (!write_ready_callback_.is_null())
130 write_ready_callback_.Run();
131 else
132 NOTREACHED();
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)),
140 base::Closure()),
141 accept_socket_(NULL),
142 accept_address_(NULL),
143 read_watcher_(base::Bind(&TCPSocketLibevent::DidCompleteRead,
144 base::Unretained(this)),
145 base::Closure()),
146 write_watcher_(base::Closure(),
147 base::Bind(&TCPSocketLibevent::DidCompleteConnectOrWrite,
148 base::Unretained(this))),
149 read_buf_len_(0),
150 write_buf_len_(0),
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);
168 Close();
171 int TCPSocketLibevent::Open(AddressFamily family) {
172 DCHECK(CalledOnValidThread());
173 DCHECK_EQ(socket_, kInvalidSocket);
175 socket_ = CreatePlatformSocket(ConvertAddressFamily(family), SOCK_STREAM,
176 IPPROTO_TCP);
177 if (socket_ < 0) {
178 PLOG(ERROR) << "CreatePlatformSocket() returned an error";
179 return MapSystemError(errno);
182 if (SetNonBlocking(socket_)) {
183 int result = MapSystemError(errno);
184 Close();
185 return result;
188 return OK;
191 int TCPSocketLibevent::AdoptConnectedSocket(int socket,
192 const IPEndPoint& peer_address) {
193 DCHECK(CalledOnValidThread());
194 DCHECK_EQ(socket_, kInvalidSocket);
196 socket_ = socket;
198 if (SetNonBlocking(socket_)) {
199 int result = MapSystemError(errno);
200 Close();
201 return result;
204 peer_address_.reset(new IPEndPoint(peer_address));
206 return OK;
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);
218 if (result < 0) {
219 PLOG(ERROR) << "bind() returned an error";
220 return MapSystemError(errno);
223 return OK;
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);
232 if (result < 0) {
233 PLOG(ERROR) << "listen() returned an error";
234 return MapSystemError(errno);
237 return OK;
240 int TCPSocketLibevent::Accept(scoped_ptr<TCPSocketLibevent>* socket,
241 IPEndPoint* address,
242 const CompletionCallback& callback) {
243 DCHECK(CalledOnValidThread());
244 DCHECK(socket);
245 DCHECK(address);
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;
266 return result;
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()
277 // is not allowed.
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
281 // POSIX.
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;
295 } else {
296 DoConnectComplete(rv);
299 return rv;
302 bool TCPSocketLibevent::IsConnected() const {
303 DCHECK(CalledOnValidThread());
305 if (socket_ == kInvalidSocket || waiting_connect_)
306 return false;
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_.
311 return true;
314 // Check if connection is alive.
315 char c;
316 int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK));
317 if (rv == 0)
318 return false;
319 if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
320 return false;
322 return true;
325 bool TCPSocketLibevent::IsConnectedAndIdle() const {
326 DCHECK(CalledOnValidThread());
328 if (socket_ == kInvalidSocket || waiting_connect_)
329 return false;
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
335 // unexpectedly.
336 char c;
337 int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK));
338 if (rv >= 0)
339 return false;
340 if (errno != EAGAIN && errno != EWOULDBLOCK)
341 return false;
343 return true;
346 int TCPSocketLibevent::Read(IOBuffer* buf,
347 int buf_len,
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));
358 if (nread >= 0) {
359 base::StatsCounter read_bytes("tcp.read_bytes");
360 read_bytes.Add(nread);
361 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, nread,
362 buf->data());
363 RecordFastOpenStatus();
364 return nread;
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));
370 return net_error;
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);
380 read_buf_ = buf;
381 read_buf_len_ = buf_len;
382 read_callback_ = callback;
383 return ERR_IO_PENDING;
386 int TCPSocketLibevent::Write(IOBuffer* buf,
387 int buf_len,
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);
398 if (nwrite >= 0) {
399 base::StatsCounter write_bytes("tcp.write_bytes");
400 write_bytes.Add(nwrite);
401 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, nwrite,
402 buf->data());
403 return 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));
409 return net_error;
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);
419 write_buf_ = buf;
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());
427 DCHECK(address);
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;
435 return OK;
438 int TCPSocketLibevent::GetPeerAddress(IPEndPoint* address) const {
439 DCHECK(CalledOnValidThread());
440 DCHECK(address);
441 if (!IsConnected())
442 return ERR_SOCKET_NOT_CONNECTED;
443 *address = *peer_address_;
444 return OK;
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
469 // behavior.
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
474 // to 3.9.
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));
480 if (rv < 0)
481 return MapSystemError(errno);
482 return OK;
485 bool TCPSocketLibevent::SetReceiveBufferSize(int32 size) {
486 DCHECK(CalledOnValidThread());
487 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF,
488 reinterpret_cast<const char*>(&size),
489 sizeof(size));
490 DCHECK(!rv) << "Could not set socket receive buffer size: " << errno;
491 return rv == 0;
494 bool TCPSocketLibevent::SetSendBufferSize(int32 size) {
495 DCHECK(CalledOnValidThread());
496 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
497 reinterpret_cast<const char*>(&size),
498 sizeof(size));
499 DCHECK(!rv) << "Could not set socket send buffer size: " << errno;
500 return rv == 0;
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();
517 DCHECK(ok);
518 ok = read_socket_watcher_.StopWatchingFileDescriptor();
519 DCHECK(ok);
520 ok = write_socket_watcher_.StopWatchingFileDescriptor();
521 DCHECK(ok);
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()) {
536 read_buf_ = NULL;
537 read_buf_len_ = 0;
538 read_callback_.Reset();
541 if (!write_callback_.is_null()) {
542 write_buf_ = NULL;
543 write_buf_len_ = 0;
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);
563 } else {
564 NOTREACHED();
568 void TCPSocketLibevent::EndLoggingMultipleConnectAttempts(int net_error) {
569 if (logging_multiple_connect_attempts_) {
570 LogConnectEnd(net_error);
571 logging_multiple_connect_attempts_ = false;
572 } else {
573 NOTREACHED();
577 int TCPSocketLibevent::AcceptInternal(scoped_ptr<TCPSocketLibevent>* socket,
578 IPEndPoint* address) {
579 SockaddrStorage storage;
580 int new_socket = HANDLE_EINTR(accept(socket_,
581 storage.addr,
582 &storage.addr_len));
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);
587 return net_error;
590 IPEndPoint ip_end_point;
591 if (!ip_end_point.FromSockAddr(storage.addr, storage.addr_len)) {
592 NOTREACHED();
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);
604 return 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));
610 return OK;
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!
627 return OK;
629 } else {
630 // With TCP FastOpen, we pretend that the socket is connected.
631 DCHECK(!tcp_fastopen_connected_);
632 return OK;
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;
657 if (result != OK) {
658 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT,
659 NetLog::IntegerCallback("os_error", os_error));
660 } else {
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) {
677 if (net_error == OK)
678 UpdateConnectionTypeHistograms(CONNECTION_ANY);
680 if (net_error != OK) {
681 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT, net_error);
682 return;
685 SockaddrStorage storage;
686 int rv = getsockname(socket_, storage.addr, &storage.addr_len);
687 if (rv != 0) {
688 PLOG(ERROR) << "getsockname() [rv: " << rv << "] error: ";
689 NOTREACHED();
690 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT, rv);
691 return;
694 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT,
695 CreateNetLogSourceAddressCallback(storage.addr,
696 storage.addr_len));
699 void TCPSocketLibevent::DidCompleteRead() {
700 RecordFastOpenStatus();
701 if (read_callback_.is_null())
702 return;
704 int bytes_transferred;
705 bytes_transferred = HANDLE_EINTR(read(socket_, read_buf_->data(),
706 read_buf_len_));
708 int result;
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,
714 read_buf_->data());
715 } else {
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) {
724 read_buf_ = NULL;
725 read_buf_len_ = 0;
726 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
727 DCHECK(ok);
728 base::ResetAndReturn(&read_callback_).Run(result);
732 void TCPSocketLibevent::DidCompleteWrite() {
733 if (write_callback_.is_null())
734 return;
736 int bytes_transferred;
737 bytes_transferred = HANDLE_EINTR(write(socket_, write_buf_->data(),
738 write_buf_len_));
740 int result;
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,
746 write_buf_->data());
747 } else {
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) {
756 write_buf_ = NULL;
757 write_buf_len_ = 0;
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.
767 int os_error = 0;
768 socklen_t len = sizeof(os_error);
769 if (getsockopt(socket_, SOL_SOCKET, SO_ERROR, &os_error, &len) < 0)
770 os_error = errno;
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();
785 else
786 DidCompleteWrite();
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();
797 DCHECK(ok);
798 CompletionCallback callback = accept_callback_;
799 accept_callback_.Reset();
800 callback.Run(result);
804 int TCPSocketLibevent::InternalWrite(IOBuffer* buf, int buf_len) {
805 int nwrite;
806 if (use_tcp_fastopen_ && !tcp_fastopen_connected_) {
807 SockaddrStorage storage;
808 if (!peer_address_->ToSockAddr(storage.addr, &storage.addr_len)) {
809 errno = EINVAL;
810 return -1;
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
818 // Open via sysctl.
819 flags |= MSG_NOSIGNAL;
820 #endif // defined(OS_LINUX)
821 nwrite = HANDLE_EINTR(sendto(socket_,
822 buf->data(),
823 buf_len,
824 flags,
825 storage.addr,
826 storage.addr_len));
827 tcp_fastopen_connected_ = true;
829 if (nwrite < 0) {
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
836 // kernel space.
837 if (errno == EINPROGRESS) {
838 errno = EAGAIN;
839 fast_open_status_ = FAST_OPEN_SLOW_CONNECT_RETURN;
840 } else {
841 fast_open_status_ = FAST_OPEN_ERROR;
843 } else {
844 fast_open_status_ = FAST_OPEN_FAST_CONNECT_RETURN;
846 } else {
847 nwrite = HANDLE_EINTR(write(socket_, buf->data(), buf_len));
849 return nwrite;
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.
861 tcp_info info;
862 socklen_t info_len = sizeof(tcp_info);
863 getsockopt_success =
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);
868 #endif
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);
873 } else {
874 fast_open_status_ = (server_acked_data ? FAST_OPEN_NO_SYN_DATA_ACK :
875 FAST_OPEN_NO_SYN_DATA_NACK);
877 } else {
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);
885 } // namespace net