• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2010 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_client_socket.h"
6 
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <netdb.h>
10 #include <sys/socket.h>
11 #include <netinet/tcp.h>
12 #if defined(OS_POSIX)
13 #include <netinet/in.h>
14 #endif
15 
16 #include "base/eintr_wrapper.h"
17 #include "base/logging.h"
18 #include "base/message_loop.h"
19 #include "base/metrics/stats_counters.h"
20 #include "base/string_util.h"
21 #include "net/base/address_list_net_log_param.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 #if defined(USE_SYSTEM_LIBEVENT)
30 #include <event.h>
31 #else
32 #include "third_party/libevent/event.h"
33 #endif
34 #ifdef ANDROID
35 #include <cutils/qtaguid.h>
36 #endif
37 
38 namespace net {
39 
40 namespace {
41 
42 const int kInvalidSocket = -1;
43 
44 // DisableNagle turns off buffering in the kernel. By default, TCP sockets will
45 // wait up to 200ms for more data to complete a packet before transmitting.
46 // After calling this function, the kernel will not wait. See TCP_NODELAY in
47 // `man 7 tcp`.
DisableNagle(int fd)48 int DisableNagle(int fd) {
49   int on = 1;
50   return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
51 }
52 
53 // SetTCPKeepAlive sets SO_KEEPALIVE.
SetTCPKeepAlive(int fd)54 void SetTCPKeepAlive(int fd) {
55   int optval = 1;
56   socklen_t optlen = sizeof(optval);
57   if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen)) {
58     PLOG(ERROR) << "Failed to set SO_KEEPALIVE on fd: " << fd;
59     return;
60   }
61 #if defined(OS_LINUX)
62   // Set seconds until first TCP keep alive.
63 #ifdef ANDROID
64   optval = 25;
65 #else
66   optval = 45;
67 #endif
68   if (setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &optval, optlen)) {
69     PLOG(ERROR) << "Failed to set TCP_KEEPIDLE on fd: " << fd;
70     return;
71   }
72   // Set seconds between TCP keep alives.
73   if (setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &optval, optlen)) {
74     PLOG(ERROR) << "Failed to set TCP_KEEPINTVL on fd: " << fd;
75     return;
76   }
77 #endif
78 }
79 
MapConnectError(int os_error)80 int MapConnectError(int os_error) {
81   switch (os_error) {
82     case EACCES:
83       return ERR_NETWORK_ACCESS_DENIED;
84     case ETIMEDOUT:
85       return ERR_CONNECTION_TIMED_OUT;
86     default: {
87       int net_error = MapSystemError(os_error);
88       if (net_error == ERR_FAILED)
89         return ERR_CONNECTION_FAILED;  // More specific than ERR_FAILED.
90 
91       // Give a more specific error when the user is offline.
92       if (net_error == ERR_ADDRESS_UNREACHABLE &&
93           NetworkChangeNotifier::IsOffline()) {
94         return ERR_INTERNET_DISCONNECTED;
95       }
96       return net_error;
97     }
98   }
99 }
100 
101 }  // namespace
102 
103 //-----------------------------------------------------------------------------
104 
TCPClientSocketLibevent(const AddressList & addresses,net::NetLog * net_log,const net::NetLog::Source & source)105 TCPClientSocketLibevent::TCPClientSocketLibevent(
106     const AddressList& addresses,
107     net::NetLog* net_log,
108     const net::NetLog::Source& source)
109     : socket_(kInvalidSocket),
110       addresses_(addresses),
111       current_ai_(NULL),
112       read_watcher_(this),
113       write_watcher_(this),
114       read_callback_(NULL),
115       write_callback_(NULL),
116       next_connect_state_(CONNECT_STATE_NONE),
117       connect_os_error_(0),
118       net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)),
119       previously_disconnected_(false),
120       use_tcp_fastopen_(false),
121       tcp_fastopen_connected_(false)
122 #ifdef ANDROID
123       , wait_for_connect_(false)
124       , valid_uid_(false)
125       , calling_uid_(0)
126 #endif
127 {
128   scoped_refptr<NetLog::EventParameters> params;
129   if (source.is_valid())
130     params = new NetLogSourceParameter("source_dependency", source);
131   net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, params);
132 
133   if (is_tcp_fastopen_enabled())
134     use_tcp_fastopen_ = true;
135 }
136 
~TCPClientSocketLibevent()137 TCPClientSocketLibevent::~TCPClientSocketLibevent() {
138   Disconnect();
139   net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE, NULL);
140 }
141 
AdoptSocket(int socket)142 void TCPClientSocketLibevent::AdoptSocket(int socket) {
143   DCHECK_EQ(socket_, kInvalidSocket);
144   socket_ = socket;
145   int error = SetupSocket();
146   DCHECK_EQ(0, error);
147   // This is to make GetPeerAddress work. It's up to the test that is calling
148   // this function to ensure that address_ contains a reasonable address for
149   // this socket. (i.e. at least match IPv4 vs IPv6!).
150   current_ai_ = addresses_.head();
151   use_history_.set_was_ever_connected();
152 }
153 
Connect(CompletionCallback * callback,bool wait_for_connect,bool valid_uid,uid_t calling_uid)154 int TCPClientSocketLibevent::Connect(CompletionCallback* callback
155 #ifdef ANDROID
156                                      , bool wait_for_connect
157                                      , bool valid_uid
158                                      , uid_t calling_uid
159 #endif
160                                     ) {
161 #ifdef ANDROID
162   wait_for_connect_ = wait_for_connect;
163   valid_uid_ = valid_uid;
164   calling_uid_ = calling_uid;
165 #endif
166   DCHECK(CalledOnValidThread());
167 
168   // If already connected, then just return OK.
169   if (socket_ != kInvalidSocket)
170     return OK;
171 
172   base::StatsCounter connects("tcp.connect");
173   connects.Increment();
174 
175   DCHECK(!waiting_connect());
176 
177   net_log_.BeginEvent(
178       NetLog::TYPE_TCP_CONNECT,
179       make_scoped_refptr(new AddressListNetLogParam(addresses_)));
180 
181   // We will try to connect to each address in addresses_. Start with the
182   // first one in the list.
183   next_connect_state_ = CONNECT_STATE_CONNECT;
184   current_ai_ = addresses_.head();
185 
186   int rv = DoConnectLoop(OK);
187   if (rv == ERR_IO_PENDING) {
188     // Synchronous operation not supported.
189     DCHECK(callback);
190     write_callback_ = callback;
191   } else {
192     LogConnectCompletion(rv);
193   }
194 
195   return rv;
196 }
197 
DoConnectLoop(int result)198 int TCPClientSocketLibevent::DoConnectLoop(int result) {
199   DCHECK_NE(next_connect_state_, CONNECT_STATE_NONE);
200 
201   int rv = result;
202   do {
203     ConnectState state = next_connect_state_;
204     next_connect_state_ = CONNECT_STATE_NONE;
205     switch (state) {
206       case CONNECT_STATE_CONNECT:
207         DCHECK_EQ(OK, rv);
208         rv = DoConnect();
209         break;
210       case CONNECT_STATE_CONNECT_COMPLETE:
211         rv = DoConnectComplete(rv);
212         break;
213       default:
214         LOG(DFATAL) << "bad state";
215         rv = ERR_UNEXPECTED;
216         break;
217     }
218   } while (rv != ERR_IO_PENDING && next_connect_state_ != CONNECT_STATE_NONE);
219 
220   return rv;
221 }
222 
DoConnect()223 int TCPClientSocketLibevent::DoConnect() {
224   DCHECK(current_ai_);
225 
226   DCHECK_EQ(0, connect_os_error_);
227 
228   if (previously_disconnected_) {
229     use_history_.Reset();
230     previously_disconnected_ = false;
231   }
232 
233   net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT,
234                       make_scoped_refptr(new NetLogStringParameter(
235                           "address", NetAddressToStringWithPort(current_ai_))));
236 
237   next_connect_state_ = CONNECT_STATE_CONNECT_COMPLETE;
238 
239   // Create a non-blocking socket.
240   connect_os_error_ = CreateSocket(current_ai_);
241   if (connect_os_error_)
242     return MapSystemError(connect_os_error_);
243 
244   // Connect the socket.
245   if (!use_tcp_fastopen_) {
246     if (!HANDLE_EINTR(connect(socket_, current_ai_->ai_addr,
247                               static_cast<int>(current_ai_->ai_addrlen)))) {
248       // Connected without waiting!
249       return OK;
250 #ifdef ANDROID
251     } else if (errno == EINPROGRESS && wait_for_connect_) {
252       fd_set writeset;
253       FD_ZERO(&writeset);
254       FD_SET(socket_, &writeset);
255       timeval tv;
256       tv.tv_sec = 20;
257       tv.tv_usec = 0;
258       int res = HANDLE_EINTR(select(socket_ + 1, 0, &writeset, 0, &tv));
259       if (res > 0)
260         return OK;
261       return MapConnectError(ETIMEDOUT);
262 #endif
263     }
264   } else {
265     // With TCP FastOpen, we pretend that the socket is connected.
266     DCHECK(!tcp_fastopen_connected_);
267     return OK;
268   }
269 
270   // Check if the connect() failed synchronously.
271   connect_os_error_ = errno;
272   if (connect_os_error_ != EINPROGRESS)
273     return MapConnectError(connect_os_error_);
274 
275   // Otherwise the connect() is going to complete asynchronously, so watch
276   // for its completion.
277   if (!MessageLoopForIO::current()->WatchFileDescriptor(
278           socket_, true, MessageLoopForIO::WATCH_WRITE, &write_socket_watcher_,
279           &write_watcher_)) {
280     connect_os_error_ = errno;
281     DVLOG(1) << "WatchFileDescriptor failed: " << connect_os_error_;
282     return MapSystemError(connect_os_error_);
283   }
284 
285   return ERR_IO_PENDING;
286 }
287 
DoConnectComplete(int result)288 int TCPClientSocketLibevent::DoConnectComplete(int result) {
289   // Log the end of this attempt (and any OS error it threw).
290   int os_error = connect_os_error_;
291   connect_os_error_ = 0;
292   scoped_refptr<NetLog::EventParameters> params;
293   if (result != OK)
294     params = new NetLogIntegerParameter("os_error", os_error);
295   net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT, params);
296 
297   write_socket_watcher_.StopWatchingFileDescriptor();
298 
299   if (result == OK) {
300     use_history_.set_was_ever_connected();
301     return OK;  // Done!
302   }
303 
304   // Close whatever partially connected socket we currently have.
305   DoDisconnect();
306 
307   // Try to fall back to the next address in the list.
308   if (current_ai_->ai_next) {
309     next_connect_state_ = CONNECT_STATE_CONNECT;
310     current_ai_ = current_ai_->ai_next;
311     return OK;
312   }
313 
314   // Otherwise there is nothing to fall back to, so give up.
315   return result;
316 }
317 
Disconnect()318 void TCPClientSocketLibevent::Disconnect() {
319   DCHECK(CalledOnValidThread());
320 
321   DoDisconnect();
322   current_ai_ = NULL;
323 }
324 
DoDisconnect()325 void TCPClientSocketLibevent::DoDisconnect() {
326   if (socket_ == kInvalidSocket)
327     return;
328 
329   bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
330   DCHECK(ok);
331   ok = write_socket_watcher_.StopWatchingFileDescriptor();
332   DCHECK(ok);
333 
334 #ifdef ANDROID
335   if (valid_uid_)
336     qtaguid_untagSocket(socket_);
337 #endif
338 
339   if (HANDLE_EINTR(close(socket_)) < 0)
340     PLOG(ERROR) << "close";
341   socket_ = kInvalidSocket;
342   previously_disconnected_ = true;
343 }
344 
IsConnected() const345 bool TCPClientSocketLibevent::IsConnected() const {
346   DCHECK(CalledOnValidThread());
347 
348   if (socket_ == kInvalidSocket || waiting_connect())
349     return false;
350 
351   // Check if connection is alive.
352   char c;
353   int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK));
354   if (rv == 0)
355     return false;
356   if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
357     return false;
358 
359   return true;
360 }
361 
IsConnectedAndIdle() const362 bool TCPClientSocketLibevent::IsConnectedAndIdle() const {
363   DCHECK(CalledOnValidThread());
364 
365   if (socket_ == kInvalidSocket || waiting_connect())
366     return false;
367 
368   // Check if connection is alive and we haven't received any data
369   // unexpectedly.
370   char c;
371   int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK));
372   if (rv >= 0)
373     return false;
374   if (errno != EAGAIN && errno != EWOULDBLOCK)
375     return false;
376 
377   return true;
378 }
379 
Read(IOBuffer * buf,int buf_len,CompletionCallback * callback)380 int TCPClientSocketLibevent::Read(IOBuffer* buf,
381                                   int buf_len,
382                                   CompletionCallback* callback) {
383   DCHECK(CalledOnValidThread());
384   DCHECK_NE(kInvalidSocket, socket_);
385   DCHECK(!waiting_connect());
386   DCHECK(!read_callback_);
387   // Synchronous operation not supported
388   DCHECK(callback);
389   DCHECK_GT(buf_len, 0);
390 
391   int nread = HANDLE_EINTR(read(socket_, buf->data(), buf_len));
392   if (nread >= 0) {
393     base::StatsCounter read_bytes("tcp.read_bytes");
394     read_bytes.Add(nread);
395     if (nread > 0)
396       use_history_.set_was_used_to_convey_data();
397     LogByteTransfer(
398         net_log_, NetLog::TYPE_SOCKET_BYTES_RECEIVED, nread, buf->data());
399     return nread;
400   }
401   if (errno != EAGAIN && errno != EWOULDBLOCK) {
402     DVLOG(1) << "read failed, errno " << errno;
403     return MapSystemError(errno);
404   }
405 
406   if (!MessageLoopForIO::current()->WatchFileDescriptor(
407           socket_, true, MessageLoopForIO::WATCH_READ,
408           &read_socket_watcher_, &read_watcher_)) {
409     DVLOG(1) << "WatchFileDescriptor failed on read, errno " << errno;
410     return MapSystemError(errno);
411   }
412 
413   read_buf_ = buf;
414   read_buf_len_ = buf_len;
415   read_callback_ = callback;
416   return ERR_IO_PENDING;
417 }
418 
Write(IOBuffer * buf,int buf_len,CompletionCallback * callback)419 int TCPClientSocketLibevent::Write(IOBuffer* buf,
420                                    int buf_len,
421                                    CompletionCallback* callback) {
422   DCHECK(CalledOnValidThread());
423   DCHECK_NE(kInvalidSocket, socket_);
424   DCHECK(!waiting_connect());
425   DCHECK(!write_callback_);
426   // Synchronous operation not supported
427   DCHECK(callback);
428   DCHECK_GT(buf_len, 0);
429 
430   int nwrite = InternalWrite(buf, buf_len);
431   if (nwrite >= 0) {
432     base::StatsCounter write_bytes("tcp.write_bytes");
433     write_bytes.Add(nwrite);
434     if (nwrite > 0)
435       use_history_.set_was_used_to_convey_data();
436     LogByteTransfer(
437         net_log_, NetLog::TYPE_SOCKET_BYTES_SENT, nwrite, buf->data());
438     return nwrite;
439   }
440   if (errno != EAGAIN && errno != EWOULDBLOCK)
441     return MapSystemError(errno);
442 
443   if (!MessageLoopForIO::current()->WatchFileDescriptor(
444           socket_, true, MessageLoopForIO::WATCH_WRITE,
445           &write_socket_watcher_, &write_watcher_)) {
446     DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno;
447     return MapSystemError(errno);
448   }
449 
450   write_buf_ = buf;
451   write_buf_len_ = buf_len;
452   write_callback_ = callback;
453   return ERR_IO_PENDING;
454 }
455 
InternalWrite(IOBuffer * buf,int buf_len)456 int TCPClientSocketLibevent::InternalWrite(IOBuffer* buf, int buf_len) {
457   int nwrite;
458   if (use_tcp_fastopen_ && !tcp_fastopen_connected_) {
459     // We have a limited amount of data to send in the SYN packet.
460     int kMaxFastOpenSendLength = 1420;
461 
462     buf_len = std::min(kMaxFastOpenSendLength, buf_len);
463 
464     int flags = 0x20000000;  // Magic flag to enable TCP_FASTOPEN
465     nwrite = HANDLE_EINTR(sendto(socket_,
466                                  buf->data(),
467                                  buf_len,
468                                  flags,
469                                  current_ai_->ai_addr,
470                                  static_cast<int>(current_ai_->ai_addrlen)));
471     tcp_fastopen_connected_ = true;
472 
473     if (nwrite < 0) {
474       // Non-blocking mode is returning EINPROGRESS rather than EAGAIN.
475       if (errno == EINPROGRESS)
476          errno = EAGAIN;
477 
478       // Unlike "normal" nonblocking sockets, the data is already queued,
479       // so tell the app that we've consumed it.
480       return buf_len;
481     }
482   } else {
483     nwrite = HANDLE_EINTR(write(socket_, buf->data(), buf_len));
484   }
485   return nwrite;
486 }
487 
SetReceiveBufferSize(int32 size)488 bool TCPClientSocketLibevent::SetReceiveBufferSize(int32 size) {
489   DCHECK(CalledOnValidThread());
490   int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF,
491       reinterpret_cast<const char*>(&size),
492       sizeof(size));
493   DCHECK(!rv) << "Could not set socket receive buffer size: " << errno;
494   return rv == 0;
495 }
496 
SetSendBufferSize(int32 size)497 bool TCPClientSocketLibevent::SetSendBufferSize(int32 size) {
498   DCHECK(CalledOnValidThread());
499   int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
500       reinterpret_cast<const char*>(&size),
501       sizeof(size));
502   DCHECK(!rv) << "Could not set socket send buffer size: " << errno;
503   return rv == 0;
504 }
505 
506 
CreateSocket(const addrinfo * ai)507 int TCPClientSocketLibevent::CreateSocket(const addrinfo* ai) {
508   socket_ = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
509   if (socket_ == kInvalidSocket)
510     return errno;
511   return SetupSocket();
512 }
513 
SetupSocket()514 int TCPClientSocketLibevent::SetupSocket() {
515   if (SetNonBlocking(socket_)) {
516     const int err = errno;
517 
518 #ifdef ANDROID
519     if (valid_uid_)
520       qtaguid_untagSocket(socket_);
521 #endif
522 
523     close(socket_);
524     socket_ = kInvalidSocket;
525     return err;
526   }
527 
528   // This mirrors the behaviour on Windows. See the comment in
529   // tcp_client_socket_win.cc after searching for "NODELAY".
530   DisableNagle(socket_);  // If DisableNagle fails, we don't care.
531 
532   // ANDROID: Disable TCP keep-alive for bug 5226268
533   // [Browser] http keep-alive packets are sent too frequently to network
534 #ifndef ANDROID
535   SetTCPKeepAlive(socket_);
536 #endif
537 
538 #ifdef ANDROID
539   if (valid_uid_)
540     qtaguid_tagSocket(socket_, geteuid(), calling_uid_);
541 #endif
542 
543   return 0;
544 }
545 
LogConnectCompletion(int net_error)546 void TCPClientSocketLibevent::LogConnectCompletion(int net_error) {
547   if (net_error == OK)
548     UpdateConnectionTypeHistograms(CONNECTION_ANY);
549 
550   if (net_error != OK) {
551     net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT, net_error);
552     return;
553   }
554 
555   struct sockaddr_storage source_address;
556   socklen_t addrlen = sizeof(source_address);
557   int rv = getsockname(
558       socket_, reinterpret_cast<struct sockaddr*>(&source_address), &addrlen);
559   if (rv != 0) {
560     PLOG(ERROR) << "getsockname() [rv: " << rv << "] error: ";
561     NOTREACHED();
562     net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT, rv);
563     return;
564   }
565 
566   const std::string source_address_str =
567       NetAddressToStringWithPort(
568           reinterpret_cast<const struct sockaddr*>(&source_address),
569           sizeof(source_address));
570   net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT,
571                     make_scoped_refptr(new NetLogStringParameter(
572                         "source address",
573                         source_address_str)));
574 }
575 
DoReadCallback(int rv)576 void TCPClientSocketLibevent::DoReadCallback(int rv) {
577   DCHECK_NE(rv, ERR_IO_PENDING);
578   DCHECK(read_callback_);
579 
580   // since Run may result in Read being called, clear read_callback_ up front.
581   CompletionCallback* c = read_callback_;
582   read_callback_ = NULL;
583   c->Run(rv);
584 }
585 
DoWriteCallback(int rv)586 void TCPClientSocketLibevent::DoWriteCallback(int rv) {
587   DCHECK_NE(rv, ERR_IO_PENDING);
588   DCHECK(write_callback_);
589 
590   // since Run may result in Write being called, clear write_callback_ up front.
591   CompletionCallback* c = write_callback_;
592   write_callback_ = NULL;
593   c->Run(rv);
594 }
595 
DidCompleteConnect()596 void TCPClientSocketLibevent::DidCompleteConnect() {
597   DCHECK_EQ(next_connect_state_, CONNECT_STATE_CONNECT_COMPLETE);
598 
599   // Get the error that connect() completed with.
600   int os_error = 0;
601   socklen_t len = sizeof(os_error);
602   if (getsockopt(socket_, SOL_SOCKET, SO_ERROR, &os_error, &len) < 0)
603     os_error = errno;
604 
605   // TODO(eroman): Is this check really necessary?
606   if (os_error == EINPROGRESS || os_error == EALREADY) {
607     NOTREACHED();  // This indicates a bug in libevent or our code.
608     return;
609   }
610 
611   connect_os_error_ = os_error;
612   int rv = DoConnectLoop(MapConnectError(os_error));
613   if (rv != ERR_IO_PENDING) {
614     LogConnectCompletion(rv);
615     DoWriteCallback(rv);
616   }
617 }
618 
DidCompleteRead()619 void TCPClientSocketLibevent::DidCompleteRead() {
620   int bytes_transferred;
621   bytes_transferred = HANDLE_EINTR(read(socket_, read_buf_->data(),
622                                         read_buf_len_));
623 
624   int result;
625   if (bytes_transferred >= 0) {
626     result = bytes_transferred;
627     base::StatsCounter read_bytes("tcp.read_bytes");
628     read_bytes.Add(bytes_transferred);
629     if (bytes_transferred > 0)
630       use_history_.set_was_used_to_convey_data();
631     LogByteTransfer(net_log_, NetLog::TYPE_SOCKET_BYTES_RECEIVED, result,
632                     read_buf_->data());
633   } else {
634     result = MapSystemError(errno);
635   }
636 
637   if (result != ERR_IO_PENDING) {
638     read_buf_ = NULL;
639     read_buf_len_ = 0;
640     bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
641     DCHECK(ok);
642     DoReadCallback(result);
643   }
644 }
645 
DidCompleteWrite()646 void TCPClientSocketLibevent::DidCompleteWrite() {
647   int bytes_transferred;
648   bytes_transferred = HANDLE_EINTR(write(socket_, write_buf_->data(),
649                                          write_buf_len_));
650 
651   int result;
652   if (bytes_transferred >= 0) {
653     result = bytes_transferred;
654     base::StatsCounter write_bytes("tcp.write_bytes");
655     write_bytes.Add(bytes_transferred);
656     if (bytes_transferred > 0)
657       use_history_.set_was_used_to_convey_data();
658     LogByteTransfer(net_log_, NetLog::TYPE_SOCKET_BYTES_SENT, result,
659                     write_buf_->data());
660   } else {
661     result = MapSystemError(errno);
662   }
663 
664   if (result != ERR_IO_PENDING) {
665     write_buf_ = NULL;
666     write_buf_len_ = 0;
667     write_socket_watcher_.StopWatchingFileDescriptor();
668     DoWriteCallback(result);
669   }
670 }
671 
GetPeerAddress(AddressList * address) const672 int TCPClientSocketLibevent::GetPeerAddress(AddressList* address) const {
673   DCHECK(CalledOnValidThread());
674   DCHECK(address);
675   if (!IsConnected())
676     return ERR_SOCKET_NOT_CONNECTED;
677   address->Copy(current_ai_, false);
678   return OK;
679 }
680 
GetLocalAddress(IPEndPoint * address) const681 int TCPClientSocketLibevent::GetLocalAddress(IPEndPoint* address) const {
682   DCHECK(CalledOnValidThread());
683   DCHECK(address);
684   if (!IsConnected())
685     return ERR_SOCKET_NOT_CONNECTED;
686 
687   struct sockaddr_storage addr_storage;
688   socklen_t addr_len = sizeof(addr_storage);
689   struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
690   if (getsockname(socket_, addr, &addr_len))
691     return MapSystemError(errno);
692   if (!address->FromSockAddr(addr, addr_len))
693     return ERR_FAILED;
694 
695   return OK;
696 }
697 
NetLog() const698 const BoundNetLog& TCPClientSocketLibevent::NetLog() const {
699   return net_log_;
700 }
701 
SetSubresourceSpeculation()702 void TCPClientSocketLibevent::SetSubresourceSpeculation() {
703   use_history_.set_subresource_speculation();
704 }
705 
SetOmniboxSpeculation()706 void TCPClientSocketLibevent::SetOmniboxSpeculation() {
707   use_history_.set_omnibox_speculation();
708 }
709 
WasEverUsed() const710 bool TCPClientSocketLibevent::WasEverUsed() const {
711   return use_history_.was_used_to_convey_data();
712 }
713 
UsingTCPFastOpen() const714 bool TCPClientSocketLibevent::UsingTCPFastOpen() const {
715   return use_tcp_fastopen_;
716 }
717 
718 }  // namespace net
719