blob: 9b47249a355cd41710e5c16fb9a64b0953b95814 [file] [log] [blame]
[email protected]fe89ea72011-05-12 02:02:401// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]36987e92008-09-18 18:46:262// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]7f7e92392010-10-26 18:29:295#include "net/socket/tcp_client_socket.h"
[email protected]36987e92008-09-18 18:46:266
7#include <errno.h>
8#include <fcntl.h>
9#include <netdb.h>
10#include <sys/socket.h>
[email protected]39fbd8e2010-01-20 17:55:4811#include <netinet/tcp.h>
[email protected]e39333ec2010-05-19 18:17:5312#if defined(OS_POSIX)
13#include <netinet/in.h>
14#endif
[email protected]36987e92008-09-18 18:46:2615
[email protected]157c61b2009-05-01 21:37:3116#include "base/eintr_wrapper.h"
[email protected]7faaf8642010-05-19 21:41:4017#include "base/logging.h"
[email protected]36987e92008-09-18 18:46:2618#include "base/message_loop.h"
[email protected]835d7c82010-10-14 04:38:3819#include "base/metrics/stats_counters.h"
[email protected]1ea316d2008-12-30 21:22:4620#include "base/string_util.h"
[email protected]eb8605c2010-05-21 22:17:4721#include "net/base/address_list_net_log_param.h"
[email protected]93e79012011-01-26 04:13:5922#include "net/base/connection_type_histograms.h"
[email protected]597cf6e2009-05-29 09:43:2623#include "net/base/io_buffer.h"
[email protected]e7f74da2011-04-19 23:49:3524#include "net/base/ip_endpoint.h"
[email protected]36987e92008-09-18 18:46:2625#include "net/base/net_errors.h"
[email protected]9e743cd2010-03-16 07:03:5326#include "net/base/net_log.h"
[email protected]4b32be92010-05-20 03:21:4227#include "net/base/net_util.h"
[email protected]2d3b7762010-10-09 00:35:4728#include "net/base/network_change_notifier.h"
[email protected]36987e92008-09-18 18:46:2629
30namespace net {
31
[email protected]834bbfa2009-05-22 06:24:2732namespace {
33
[email protected]4b32be92010-05-20 03:21:4234const int kInvalidSocket = -1;
[email protected]39fbd8e2010-01-20 17:55:4835
36// DisableNagle turns off buffering in the kernel. By default, TCP sockets will
37// wait up to 200ms for more data to complete a packet before transmitting.
38// After calling this function, the kernel will not wait. See TCP_NODELAY in
39// `man 7 tcp`.
40int DisableNagle(int fd) {
41 int on = 1;
42 return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
[email protected]36987e92008-09-18 18:46:2643}
44
[email protected]cd2fbf52011-01-14 20:41:2745// SetTCPKeepAlive sets SO_KEEPALIVE.
46void SetTCPKeepAlive(int fd) {
47 int optval = 1;
48 socklen_t optlen = sizeof(optval);
49 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen)) {
50 PLOG(ERROR) << "Failed to set SO_KEEPALIVE on fd: " << fd;
51 return;
52 }
53#if defined(OS_LINUX)
54 // Set seconds until first TCP keep alive.
55 optval = 45;
56 if (setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &optval, optlen)) {
57 PLOG(ERROR) << "Failed to set TCP_KEEPIDLE on fd: " << fd;
58 return;
59 }
60 // Set seconds between TCP keep alives.
61 if (setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &optval, optlen)) {
62 PLOG(ERROR) << "Failed to set TCP_KEEPINTVL on fd: " << fd;
63 return;
64 }
65#endif
66}
67
[email protected]03ec25382011-05-27 21:50:2868// Sets socket parameters. Returns the OS error code (or 0 on
69// success).
70int SetupSocket(int socket) {
71 if (SetNonBlocking(socket))
72 return errno;
73
74 // This mirrors the behaviour on Windows. See the comment in
75 // tcp_client_socket_win.cc after searching for "NODELAY".
76 DisableNagle(socket); // If DisableNagle fails, we don't care.
77 SetTCPKeepAlive(socket);
78
79 return 0;
80}
81
82// Creates a new socket and sets default parameters for it. Returns
83// the OS error code (or 0 on success).
84int CreateSocket(int family, int* socket) {
85 *socket = ::socket(family, SOCK_STREAM, IPPROTO_TCP);
86 if (*socket == kInvalidSocket)
87 return errno;
88 int error = SetupSocket(*socket);
89 if (error) {
90 if (HANDLE_EINTR(close(*socket)) < 0)
91 PLOG(ERROR) << "close";
92 *socket = kInvalidSocket;
93 return error;
94 }
95 return 0;
96}
97
[email protected]7ba1d1c2009-11-10 02:27:2098int MapConnectError(int os_error) {
99 switch (os_error) {
[email protected]e5925962010-11-02 14:37:14100 case EACCES:
101 return ERR_NETWORK_ACCESS_DENIED;
[email protected]c53976d52009-08-07 18:58:37102 case ETIMEDOUT:
103 return ERR_CONNECTION_TIMED_OUT;
[email protected]d3d82852009-11-05 03:06:08104 default: {
[email protected]051e4ec2011-03-15 20:46:32105 int net_error = MapSystemError(os_error);
[email protected]d3d82852009-11-05 03:06:08106 if (net_error == ERR_FAILED)
107 return ERR_CONNECTION_FAILED; // More specific than ERR_FAILED.
[email protected]2d3b7762010-10-09 00:35:47108
109 // Give a more specific error when the user is offline.
110 if (net_error == ERR_ADDRESS_UNREACHABLE &&
111 NetworkChangeNotifier::IsOffline()) {
112 return ERR_INTERNET_DISCONNECTED;
113 }
[email protected]d3d82852009-11-05 03:06:08114 return net_error;
115 }
[email protected]c53976d52009-08-07 18:58:37116 }
117}
118
[email protected]834bbfa2009-05-22 06:24:27119} // namespace
120
[email protected]36987e92008-09-18 18:46:26121//-----------------------------------------------------------------------------
122
[email protected]0a0b7682010-08-25 17:08:07123TCPClientSocketLibevent::TCPClientSocketLibevent(
124 const AddressList& addresses,
125 net::NetLog* net_log,
126 const net::NetLog::Source& source)
[email protected]8f1915d2009-04-20 18:37:39127 : socket_(kInvalidSocket),
[email protected]03ec25382011-05-27 21:50:28128 bound_socket_(kInvalidSocket),
[email protected]8f1915d2009-04-20 18:37:39129 addresses_(addresses),
[email protected]7faaf8642010-05-19 21:41:40130 current_ai_(NULL),
[email protected]834bbfa2009-05-22 06:24:27131 read_watcher_(this),
132 write_watcher_(this),
[email protected]7faaf8642010-05-19 21:41:40133 next_connect_state_(CONNECT_STATE_NONE),
[email protected]4b32be92010-05-20 03:21:42134 connect_os_error_(0),
[email protected]4a17b672010-10-25 09:38:56135 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)),
[email protected]7f7e92392010-10-26 18:29:29136 previously_disconnected_(false),
137 use_tcp_fastopen_(false),
[email protected]5e6efa52011-06-27 17:26:41138 tcp_fastopen_connected_(false),
139 num_bytes_read_(0) {
[email protected]0a0b7682010-08-25 17:08:07140 scoped_refptr<NetLog::EventParameters> params;
141 if (source.is_valid())
142 params = new NetLogSourceParameter("source_dependency", source);
143 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, params);
[email protected]7f7e92392010-10-26 18:29:29144
145 if (is_tcp_fastopen_enabled())
146 use_tcp_fastopen_ = true;
[email protected]36987e92008-09-18 18:46:26147}
148
[email protected]8f1915d2009-04-20 18:37:39149TCPClientSocketLibevent::~TCPClientSocketLibevent() {
[email protected]36987e92008-09-18 18:46:26150 Disconnect();
[email protected]06650c52010-06-03 00:49:17151 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE, NULL);
[email protected]36987e92008-09-18 18:46:26152}
153
[email protected]03ec25382011-05-27 21:50:28154int TCPClientSocketLibevent::AdoptSocket(int socket) {
[email protected]2d6e77832010-11-10 22:13:46155 DCHECK_EQ(socket_, kInvalidSocket);
[email protected]03ec25382011-05-27 21:50:28156
157 int error = SetupSocket(socket);
158 if (error)
159 return MapSystemError(error);
160
[email protected]2d6e77832010-11-10 22:13:46161 socket_ = socket;
[email protected]03ec25382011-05-27 21:50:28162
163 // This is to make GetPeerAddress() work. It's up to the caller ensure
164 // that |address_| contains a reasonable address for this
165 // socket. (i.e. at least match IPv4 vs IPv6!).
[email protected]2d6e77832010-11-10 22:13:46166 current_ai_ = addresses_.head();
167 use_history_.set_was_ever_connected();
[email protected]03ec25382011-05-27 21:50:28168
169 return OK;
170}
171
172int TCPClientSocketLibevent::Bind(const IPEndPoint& address) {
173 if (current_ai_ != NULL || bind_address_.get()) {
174 // Cannot bind the socket if we are already bound connected or
175 // connecting.
176 return ERR_UNEXPECTED;
177 }
178
179 sockaddr_storage addr_storage;
180 sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
181 size_t addr_len = sizeof(addr_storage);
182 if (!address.ToSockAddr(addr, &addr_len))
183 return ERR_INVALID_ARGUMENT;
184
185 // Create |bound_socket_| and try to bound it to |address|.
186 int error = CreateSocket(address.GetFamily(), &bound_socket_);
187 if (error)
188 return MapSystemError(error);
189
190 if (HANDLE_EINTR(bind(bound_socket_, addr, addr_len))) {
191 error = errno;
192 if (HANDLE_EINTR(close(bound_socket_)) < 0)
193 PLOG(ERROR) << "close";
194 bound_socket_ = kInvalidSocket;
195 return MapSystemError(error);
196 }
197
198 bind_address_.reset(new IPEndPoint(address));
199
200 return 0;
[email protected]2d6e77832010-11-10 22:13:46201}
202
[email protected]dbf036f2011-12-06 23:33:24203int TCPClientSocketLibevent::Connect(const CompletionCallback& callback) {
204 DCHECK(CalledOnValidThread());
205
206 // If already connected, then just return OK.
207 if (socket_ != kInvalidSocket)
208 return OK;
209
210 base::StatsCounter connects("tcp.connect");
211 connects.Increment();
212
213 DCHECK(!waiting_connect());
214
215 net_log_.BeginEvent(
216 NetLog::TYPE_TCP_CONNECT,
217 make_scoped_refptr(new AddressListNetLogParam(addresses_)));
218
219 // We will try to connect to each address in addresses_. Start with the
220 // first one in the list.
221 next_connect_state_ = CONNECT_STATE_CONNECT;
222 current_ai_ = addresses_.head();
223
224 int rv = DoConnectLoop(OK);
225 if (rv == ERR_IO_PENDING) {
226 // Synchronous operation not supported.
227 DCHECK(!callback.is_null());
[email protected]5a05c47a2009-11-02 23:25:19228 write_callback_ = callback;
229 } else {
[email protected]4b32be92010-05-20 03:21:42230 LogConnectCompletion(rv);
[email protected]5a05c47a2009-11-02 23:25:19231 }
232
233 return rv;
234}
235
[email protected]7faaf8642010-05-19 21:41:40236int TCPClientSocketLibevent::DoConnectLoop(int result) {
237 DCHECK_NE(next_connect_state_, CONNECT_STATE_NONE);
238
239 int rv = result;
240 do {
241 ConnectState state = next_connect_state_;
242 next_connect_state_ = CONNECT_STATE_NONE;
243 switch (state) {
244 case CONNECT_STATE_CONNECT:
245 DCHECK_EQ(OK, rv);
246 rv = DoConnect();
247 break;
248 case CONNECT_STATE_CONNECT_COMPLETE:
249 rv = DoConnectComplete(rv);
250 break;
251 default:
252 LOG(DFATAL) << "bad state";
253 rv = ERR_UNEXPECTED;
254 break;
255 }
256 } while (rv != ERR_IO_PENDING && next_connect_state_ != CONNECT_STATE_NONE);
257
258 return rv;
259}
260
[email protected]5a05c47a2009-11-02 23:25:19261int TCPClientSocketLibevent::DoConnect() {
[email protected]7faaf8642010-05-19 21:41:40262 DCHECK(current_ai_);
[email protected]36987e92008-09-18 18:46:26263
[email protected]4b32be92010-05-20 03:21:42264 DCHECK_EQ(0, connect_os_error_);
265
[email protected]4a17b672010-10-25 09:38:56266 if (previously_disconnected_) {
267 use_history_.Reset();
268 previously_disconnected_ = false;
269 }
270
[email protected]4b32be92010-05-20 03:21:42271 net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT,
[email protected]00cd9c42010-11-02 20:15:57272 make_scoped_refptr(new NetLogStringParameter(
273 "address", NetAddressToStringWithPort(current_ai_))));
[email protected]4b32be92010-05-20 03:21:42274
[email protected]7faaf8642010-05-19 21:41:40275 next_connect_state_ = CONNECT_STATE_CONNECT_COMPLETE;
[email protected]0303c1152009-09-11 23:53:14276
[email protected]03ec25382011-05-27 21:50:28277 if (bound_socket_ != kInvalidSocket) {
278 DCHECK(bind_address_.get());
279 socket_ = bound_socket_;
280 bound_socket_ = kInvalidSocket;
281 } else {
282 // Create a non-blocking socket.
283 connect_os_error_ = CreateSocket(current_ai_->ai_family, &socket_);
284 if (connect_os_error_)
285 return MapSystemError(connect_os_error_);
286
287 if (bind_address_.get()) {
288 sockaddr_storage addr_storage;
289 sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
290 size_t addr_len = sizeof(addr_storage);
291 if (!bind_address_->ToSockAddr(addr, &addr_len))
292 return ERR_INVALID_ARGUMENT;
293 if (HANDLE_EINTR(bind(socket_, addr, addr_len)))
294 return MapSystemError(errno);
295 }
296 }
[email protected]0303c1152009-09-11 23:53:14297
[email protected]7faaf8642010-05-19 21:41:40298 // Connect the socket.
[email protected]7f7e92392010-10-26 18:29:29299 if (!use_tcp_fastopen_) {
[email protected]5e6efa52011-06-27 17:26:41300 connect_start_time_ = base::TimeTicks::Now();
[email protected]7f7e92392010-10-26 18:29:29301 if (!HANDLE_EINTR(connect(socket_, current_ai_->ai_addr,
302 static_cast<int>(current_ai_->ai_addrlen)))) {
303 // Connected without waiting!
304 return OK;
305 }
306 } else {
307 // With TCP FastOpen, we pretend that the socket is connected.
308 DCHECK(!tcp_fastopen_connected_);
[email protected]7faaf8642010-05-19 21:41:40309 return OK;
[email protected]36987e92008-09-18 18:46:26310 }
311
[email protected]7faaf8642010-05-19 21:41:40312 // Check if the connect() failed synchronously.
[email protected]4b32be92010-05-20 03:21:42313 connect_os_error_ = errno;
314 if (connect_os_error_ != EINPROGRESS)
[email protected]4ea13f342010-09-10 05:29:51315 return MapConnectError(connect_os_error_);
[email protected]7faaf8642010-05-19 21:41:40316
317 // Otherwise the connect() is going to complete asynchronously, so watch
318 // for its completion.
[email protected]e45e6c02008-12-15 22:02:17319 if (!MessageLoopForIO::current()->WatchFileDescriptor(
[email protected]834bbfa2009-05-22 06:24:27320 socket_, true, MessageLoopForIO::WATCH_WRITE, &write_socket_watcher_,
321 &write_watcher_)) {
[email protected]4b32be92010-05-20 03:21:42322 connect_os_error_ = errno;
[email protected]b30a3f52010-10-16 01:05:46323 DVLOG(1) << "WatchFileDescriptor failed: " << connect_os_error_;
[email protected]051e4ec2011-03-15 20:46:32324 return MapSystemError(connect_os_error_);
[email protected]e45e6c02008-12-15 22:02:17325 }
[email protected]36987e92008-09-18 18:46:26326
[email protected]36987e92008-09-18 18:46:26327 return ERR_IO_PENDING;
328}
329
[email protected]7faaf8642010-05-19 21:41:40330int TCPClientSocketLibevent::DoConnectComplete(int result) {
[email protected]eb8605c2010-05-21 22:17:47331 // Log the end of this attempt (and any OS error it threw).
[email protected]4b32be92010-05-20 03:21:42332 int os_error = connect_os_error_;
333 connect_os_error_ = 0;
[email protected]4b32be92010-05-20 03:21:42334 scoped_refptr<NetLog::EventParameters> params;
335 if (result != OK)
336 params = new NetLogIntegerParameter("os_error", os_error);
337 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT, params);
338
[email protected]9b5614a2010-08-25 20:29:45339 if (result == OK) {
[email protected]5e6efa52011-06-27 17:26:41340 connect_time_micros_ = base::TimeTicks::Now() - connect_start_time_;
[email protected]62755f822011-06-25 02:17:56341 write_socket_watcher_.StopWatchingFileDescriptor();
[email protected]9b5614a2010-08-25 20:29:45342 use_history_.set_was_ever_connected();
[email protected]7faaf8642010-05-19 21:41:40343 return OK; // Done!
[email protected]9b5614a2010-08-25 20:29:45344 }
[email protected]7faaf8642010-05-19 21:41:40345
346 // Close whatever partially connected socket we currently have.
347 DoDisconnect();
348
349 // Try to fall back to the next address in the list.
350 if (current_ai_->ai_next) {
351 next_connect_state_ = CONNECT_STATE_CONNECT;
352 current_ai_ = current_ai_->ai_next;
353 return OK;
354 }
355
356 // Otherwise there is nothing to fall back to, so give up.
357 return result;
358}
359
[email protected]8f1915d2009-04-20 18:37:39360void TCPClientSocketLibevent::Disconnect() {
[email protected]94f808c2010-05-19 22:17:08361 DCHECK(CalledOnValidThread());
362
[email protected]7faaf8642010-05-19 21:41:40363 DoDisconnect();
364 current_ai_ = NULL;
365}
366
367void TCPClientSocketLibevent::DoDisconnect() {
[email protected]36987e92008-09-18 18:46:26368 if (socket_ == kInvalidSocket)
369 return;
370
[email protected]834bbfa2009-05-22 06:24:27371 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
372 DCHECK(ok);
373 ok = write_socket_watcher_.StopWatchingFileDescriptor();
374 DCHECK(ok);
[email protected]70eb6572010-06-23 00:37:46375 if (HANDLE_EINTR(close(socket_)) < 0)
376 PLOG(ERROR) << "close";
[email protected]36987e92008-09-18 18:46:26377 socket_ = kInvalidSocket;
[email protected]4a17b672010-10-25 09:38:56378 previously_disconnected_ = true;
[email protected]36987e92008-09-18 18:46:26379}
380
[email protected]8f1915d2009-04-20 18:37:39381bool TCPClientSocketLibevent::IsConnected() const {
[email protected]94f808c2010-05-19 22:17:08382 DCHECK(CalledOnValidThread());
383
[email protected]7faaf8642010-05-19 21:41:40384 if (socket_ == kInvalidSocket || waiting_connect())
[email protected]36987e92008-09-18 18:46:26385 return false;
386
[email protected]efaba4812011-06-22 20:31:53387 if (use_tcp_fastopen_ && !tcp_fastopen_connected_) {
388 // With TCP FastOpen, we pretend that the socket is connected.
389 // This allows GetPeerAddress() to return current_ai_ as the peer
390 // address. Since we don't fail over to the next address if
391 // sendto() fails, current_ai_ is the only possible peer address.
392 CHECK(current_ai_);
393 return true;
394 }
395
[email protected]36987e92008-09-18 18:46:26396 // Check if connection is alive.
397 char c;
[email protected]157c61b2009-05-01 21:37:31398 int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK));
[email protected]36987e92008-09-18 18:46:26399 if (rv == 0)
400 return false;
[email protected]b1670ee2008-09-23 23:32:15401 if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
402 return false;
[email protected]36987e92008-09-18 18:46:26403
404 return true;
405}
406
[email protected]8f1915d2009-04-20 18:37:39407bool TCPClientSocketLibevent::IsConnectedAndIdle() const {
[email protected]94f808c2010-05-19 22:17:08408 DCHECK(CalledOnValidThread());
409
[email protected]7faaf8642010-05-19 21:41:40410 if (socket_ == kInvalidSocket || waiting_connect())
[email protected]b2197852009-02-19 23:27:33411 return false;
412
[email protected]efaba4812011-06-22 20:31:53413 // TODO(wtc): should we also handle the TCP FastOpen case here,
414 // as we do in IsConnected()?
415
[email protected]b2197852009-02-19 23:27:33416 // Check if connection is alive and we haven't received any data
417 // unexpectedly.
418 char c;
[email protected]157c61b2009-05-01 21:37:31419 int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK));
[email protected]b2197852009-02-19 23:27:33420 if (rv >= 0)
421 return false;
422 if (errno != EAGAIN && errno != EWOULDBLOCK)
423 return false;
424
425 return true;
426}
427
[email protected]ffeb0882009-04-30 21:51:25428int TCPClientSocketLibevent::Read(IOBuffer* buf,
[email protected]8f1915d2009-04-20 18:37:39429 int buf_len,
[email protected]3f55aa12011-12-07 02:03:33430 const CompletionCallback& callback) {
431 DCHECK(CalledOnValidThread());
432 DCHECK_NE(kInvalidSocket, socket_);
433 DCHECK(!waiting_connect());
[email protected]83039bb2011-12-09 18:43:55434 DCHECK(read_callback_.is_null());
[email protected]3f55aa12011-12-07 02:03:33435 // Synchronous operation not supported
436 DCHECK(!callback.is_null());
437 DCHECK_GT(buf_len, 0);
438
439 int nread = HANDLE_EINTR(read(socket_, buf->data(), buf_len));
440 if (nread >= 0) {
441 base::StatsCounter read_bytes("tcp.read_bytes");
442 read_bytes.Add(nread);
443 num_bytes_read_ += static_cast<int64>(nread);
444 if (nread > 0)
445 use_history_.set_was_used_to_convey_data();
446 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, nread,
447 buf->data());
448 return nread;
449 }
450 if (errno != EAGAIN && errno != EWOULDBLOCK) {
451 DVLOG(1) << "read failed, errno " << errno;
452 return MapSystemError(errno);
453 }
454
455 if (!MessageLoopForIO::current()->WatchFileDescriptor(
456 socket_, true, MessageLoopForIO::WATCH_READ,
457 &read_socket_watcher_, &read_watcher_)) {
458 DVLOG(1) << "WatchFileDescriptor failed on read, errno " << errno;
459 return MapSystemError(errno);
460 }
461
462 read_buf_ = buf;
463 read_buf_len_ = buf_len;
[email protected]8f1915d2009-04-20 18:37:39464 read_callback_ = callback;
[email protected]36987e92008-09-18 18:46:26465 return ERR_IO_PENDING;
466}
467
[email protected]ffeb0882009-04-30 21:51:25468int TCPClientSocketLibevent::Write(IOBuffer* buf,
[email protected]8f1915d2009-04-20 18:37:39469 int buf_len,
[email protected]83039bb2011-12-09 18:43:55470 const CompletionCallback& callback) {
[email protected]94f808c2010-05-19 22:17:08471 DCHECK(CalledOnValidThread());
[email protected]8f1915d2009-04-20 18:37:39472 DCHECK_NE(kInvalidSocket, socket_);
[email protected]7faaf8642010-05-19 21:41:40473 DCHECK(!waiting_connect());
[email protected]83039bb2011-12-09 18:43:55474 DCHECK(write_callback_.is_null());
[email protected]36987e92008-09-18 18:46:26475 // Synchronous operation not supported
[email protected]83039bb2011-12-09 18:43:55476 DCHECK(!callback.is_null());
[email protected]8f1915d2009-04-20 18:37:39477 DCHECK_GT(buf_len, 0);
[email protected]36987e92008-09-18 18:46:26478
[email protected]7f7e92392010-10-26 18:29:29479 int nwrite = InternalWrite(buf, buf_len);
[email protected]b1670ee2008-09-23 23:32:15480 if (nwrite >= 0) {
[email protected]28620862011-03-22 23:07:19481 base::StatsCounter write_bytes("tcp.write_bytes");
[email protected]0a8b7322010-07-19 19:53:43482 write_bytes.Add(nwrite);
[email protected]9b5614a2010-08-25 20:29:45483 if (nwrite > 0)
484 use_history_.set_was_used_to_convey_data();
[email protected]267a0d66d2011-06-01 21:15:19485 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, nwrite,
486 buf->data());
[email protected]36987e92008-09-18 18:46:26487 return nwrite;
488 }
[email protected]b1670ee2008-09-23 23:32:15489 if (errno != EAGAIN && errno != EWOULDBLOCK)
[email protected]051e4ec2011-03-15 20:46:32490 return MapSystemError(errno);
[email protected]36987e92008-09-18 18:46:26491
[email protected]e45e6c02008-12-15 22:02:17492 if (!MessageLoopForIO::current()->WatchFileDescriptor(
[email protected]8f1915d2009-04-20 18:37:39493 socket_, true, MessageLoopForIO::WATCH_WRITE,
[email protected]834bbfa2009-05-22 06:24:27494 &write_socket_watcher_, &write_watcher_)) {
[email protected]b30a3f52010-10-16 01:05:46495 DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno;
[email protected]051e4ec2011-03-15 20:46:32496 return MapSystemError(errno);
[email protected]e45e6c02008-12-15 22:02:17497 }
498
[email protected]b43c97c2008-10-22 19:50:58499 write_buf_ = buf;
500 write_buf_len_ = buf_len;
[email protected]83039bb2011-12-09 18:43:55501 write_callback_ = callback;
[email protected]36987e92008-09-18 18:46:26502 return ERR_IO_PENDING;
503}
504
[email protected]7f7e92392010-10-26 18:29:29505int TCPClientSocketLibevent::InternalWrite(IOBuffer* buf, int buf_len) {
506 int nwrite;
507 if (use_tcp_fastopen_ && !tcp_fastopen_connected_) {
508 // We have a limited amount of data to send in the SYN packet.
509 int kMaxFastOpenSendLength = 1420;
510
511 buf_len = std::min(kMaxFastOpenSendLength, buf_len);
512
513 int flags = 0x20000000; // Magic flag to enable TCP_FASTOPEN
514 nwrite = HANDLE_EINTR(sendto(socket_,
515 buf->data(),
516 buf_len,
517 flags,
518 current_ai_->ai_addr,
519 static_cast<int>(current_ai_->ai_addrlen)));
520 tcp_fastopen_connected_ = true;
521
522 if (nwrite < 0) {
523 // Non-blocking mode is returning EINPROGRESS rather than EAGAIN.
524 if (errno == EINPROGRESS)
525 errno = EAGAIN;
526
527 // Unlike "normal" nonblocking sockets, the data is already queued,
528 // so tell the app that we've consumed it.
529 return buf_len;
530 }
531 } else {
532 nwrite = HANDLE_EINTR(write(socket_, buf->data(), buf_len));
533 }
534 return nwrite;
535}
536
[email protected]d3f66572009-09-09 22:38:04537bool TCPClientSocketLibevent::SetReceiveBufferSize(int32 size) {
[email protected]94f808c2010-05-19 22:17:08538 DCHECK(CalledOnValidThread());
[email protected]d3f66572009-09-09 22:38:04539 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF,
540 reinterpret_cast<const char*>(&size),
541 sizeof(size));
542 DCHECK(!rv) << "Could not set socket receive buffer size: " << errno;
543 return rv == 0;
544}
545
546bool TCPClientSocketLibevent::SetSendBufferSize(int32 size) {
[email protected]94f808c2010-05-19 22:17:08547 DCHECK(CalledOnValidThread());
[email protected]d3f66572009-09-09 22:38:04548 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
549 reinterpret_cast<const char*>(&size),
550 sizeof(size));
551 DCHECK(!rv) << "Could not set socket send buffer size: " << errno;
552 return rv == 0;
553}
554
[email protected]4b32be92010-05-20 03:21:42555void TCPClientSocketLibevent::LogConnectCompletion(int net_error) {
[email protected]93e79012011-01-26 04:13:59556 if (net_error == OK)
557 UpdateConnectionTypeHistograms(CONNECTION_ANY);
558
559 if (net_error != OK) {
[email protected]d7fd1782011-02-08 19:16:43560 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT, net_error);
[email protected]93e79012011-01-26 04:13:59561 return;
562 }
563
564 struct sockaddr_storage source_address;
565 socklen_t addrlen = sizeof(source_address);
566 int rv = getsockname(
567 socket_, reinterpret_cast<struct sockaddr*>(&source_address), &addrlen);
568 if (rv != 0) {
569 PLOG(ERROR) << "getsockname() [rv: " << rv << "] error: ";
570 NOTREACHED();
[email protected]d7fd1782011-02-08 19:16:43571 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT, rv);
[email protected]93e79012011-01-26 04:13:59572 return;
573 }
574
575 const std::string source_address_str =
576 NetAddressToStringWithPort(
577 reinterpret_cast<const struct sockaddr*>(&source_address),
578 sizeof(source_address));
579 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT,
580 make_scoped_refptr(new NetLogStringParameter(
581 "source address",
582 source_address_str)));
[email protected]4b32be92010-05-20 03:21:42583}
584
[email protected]8f1915d2009-04-20 18:37:39585void TCPClientSocketLibevent::DoReadCallback(int rv) {
586 DCHECK_NE(rv, ERR_IO_PENDING);
[email protected]83039bb2011-12-09 18:43:55587 DCHECK(!read_callback_.is_null());
[email protected]36987e92008-09-18 18:46:26588
[email protected]8f1915d2009-04-20 18:37:39589 // since Run may result in Read being called, clear read_callback_ up front.
[email protected]83039bb2011-12-09 18:43:55590 CompletionCallback c = read_callback_;
591 read_callback_.Reset();
592 c.Run(rv);
[email protected]36987e92008-09-18 18:46:26593}
594
[email protected]8f1915d2009-04-20 18:37:39595void TCPClientSocketLibevent::DoWriteCallback(int rv) {
596 DCHECK_NE(rv, ERR_IO_PENDING);
[email protected]83039bb2011-12-09 18:43:55597 DCHECK(!write_callback_.is_null());
[email protected]b43c97c2008-10-22 19:50:58598
599 // since Run may result in Write being called, clear write_callback_ up front.
[email protected]83039bb2011-12-09 18:43:55600 CompletionCallback c = write_callback_;
601 write_callback_.Reset();
602 c.Run(rv);
[email protected]b43c97c2008-10-22 19:50:58603}
604
[email protected]8f1915d2009-04-20 18:37:39605void TCPClientSocketLibevent::DidCompleteConnect() {
[email protected]7faaf8642010-05-19 21:41:40606 DCHECK_EQ(next_connect_state_, CONNECT_STATE_CONNECT_COMPLETE);
[email protected]36987e92008-09-18 18:46:26607
[email protected]7faaf8642010-05-19 21:41:40608 // Get the error that connect() completed with.
[email protected]7ba1d1c2009-11-10 02:27:20609 int os_error = 0;
610 socklen_t len = sizeof(os_error);
611 if (getsockopt(socket_, SOL_SOCKET, SO_ERROR, &os_error, &len) < 0)
612 os_error = errno;
[email protected]b1670ee2008-09-23 23:32:15613
[email protected]7faaf8642010-05-19 21:41:40614 // TODO(eroman): Is this check really necessary?
[email protected]7ba1d1c2009-11-10 02:27:20615 if (os_error == EINPROGRESS || os_error == EALREADY) {
[email protected]b1670ee2008-09-23 23:32:15616 NOTREACHED(); // This indicates a bug in libevent or our code.
[email protected]7faaf8642010-05-19 21:41:40617 return;
[email protected]36987e92008-09-18 18:46:26618 }
619
[email protected]4b32be92010-05-20 03:21:42620 connect_os_error_ = os_error;
[email protected]7faaf8642010-05-19 21:41:40621 int rv = DoConnectLoop(MapConnectError(os_error));
622 if (rv != ERR_IO_PENDING) {
[email protected]4b32be92010-05-20 03:21:42623 LogConnectCompletion(rv);
[email protected]7faaf8642010-05-19 21:41:40624 DoWriteCallback(rv);
[email protected]e45e6c02008-12-15 22:02:17625 }
[email protected]36987e92008-09-18 18:46:26626}
627
[email protected]8f1915d2009-04-20 18:37:39628void TCPClientSocketLibevent::DidCompleteRead() {
[email protected]b12c83d2008-10-16 20:39:09629 int bytes_transferred;
[email protected]157c61b2009-05-01 21:37:31630 bytes_transferred = HANDLE_EINTR(read(socket_, read_buf_->data(),
631 read_buf_len_));
[email protected]36987e92008-09-18 18:46:26632
633 int result;
[email protected]b1670ee2008-09-23 23:32:15634 if (bytes_transferred >= 0) {
[email protected]36987e92008-09-18 18:46:26635 result = bytes_transferred;
[email protected]28620862011-03-22 23:07:19636 base::StatsCounter read_bytes("tcp.read_bytes");
[email protected]9b5614a2010-08-25 20:29:45637 read_bytes.Add(bytes_transferred);
[email protected]5e6efa52011-06-27 17:26:41638 num_bytes_read_ += static_cast<int64>(bytes_transferred);
[email protected]9b5614a2010-08-25 20:29:45639 if (bytes_transferred > 0)
640 use_history_.set_was_used_to_convey_data();
[email protected]267a0d66d2011-06-01 21:15:19641 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, result,
642 read_buf_->data());
[email protected]36987e92008-09-18 18:46:26643 } else {
[email protected]051e4ec2011-03-15 20:46:32644 result = MapSystemError(errno);
[email protected]36987e92008-09-18 18:46:26645 }
646
647 if (result != ERR_IO_PENDING) {
[email protected]8f1915d2009-04-20 18:37:39648 read_buf_ = NULL;
649 read_buf_len_ = 0;
[email protected]834bbfa2009-05-22 06:24:27650 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
651 DCHECK(ok);
[email protected]8f1915d2009-04-20 18:37:39652 DoReadCallback(result);
[email protected]36987e92008-09-18 18:46:26653 }
654}
655
[email protected]8f1915d2009-04-20 18:37:39656void TCPClientSocketLibevent::DidCompleteWrite() {
[email protected]b43c97c2008-10-22 19:50:58657 int bytes_transferred;
[email protected]157c61b2009-05-01 21:37:31658 bytes_transferred = HANDLE_EINTR(write(socket_, write_buf_->data(),
659 write_buf_len_));
[email protected]b43c97c2008-10-22 19:50:58660
661 int result;
662 if (bytes_transferred >= 0) {
663 result = bytes_transferred;
[email protected]28620862011-03-22 23:07:19664 base::StatsCounter write_bytes("tcp.write_bytes");
[email protected]9b5614a2010-08-25 20:29:45665 write_bytes.Add(bytes_transferred);
666 if (bytes_transferred > 0)
667 use_history_.set_was_used_to_convey_data();
[email protected]267a0d66d2011-06-01 21:15:19668 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, result,
669 write_buf_->data());
[email protected]b43c97c2008-10-22 19:50:58670 } else {
[email protected]051e4ec2011-03-15 20:46:32671 result = MapSystemError(errno);
[email protected]36987e92008-09-18 18:46:26672 }
[email protected]b43c97c2008-10-22 19:50:58673
674 if (result != ERR_IO_PENDING) {
675 write_buf_ = NULL;
676 write_buf_len_ = 0;
[email protected]834bbfa2009-05-22 06:24:27677 write_socket_watcher_.StopWatchingFileDescriptor();
[email protected]b43c97c2008-10-22 19:50:58678 DoWriteCallback(result);
679 }
680}
681
[email protected]ac9eec62010-02-20 18:50:38682int TCPClientSocketLibevent::GetPeerAddress(AddressList* address) const {
[email protected]94f808c2010-05-19 22:17:08683 DCHECK(CalledOnValidThread());
[email protected]ac9eec62010-02-20 18:50:38684 DCHECK(address);
[email protected]176a07d2010-09-25 03:31:26685 if (!IsConnected())
[email protected]88e03fa2010-10-05 03:09:04686 return ERR_SOCKET_NOT_CONNECTED;
[email protected]fe89ea72011-05-12 02:02:40687 *address = AddressList::CreateByCopyingFirstAddress(current_ai_);
[email protected]ac9eec62010-02-20 18:50:38688 return OK;
[email protected]36987e92008-09-18 18:46:26689}
690
[email protected]e7f74da2011-04-19 23:49:35691int TCPClientSocketLibevent::GetLocalAddress(IPEndPoint* address) const {
692 DCHECK(CalledOnValidThread());
693 DCHECK(address);
694 if (!IsConnected())
695 return ERR_SOCKET_NOT_CONNECTED;
696
697 struct sockaddr_storage addr_storage;
698 socklen_t addr_len = sizeof(addr_storage);
699 struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
700 if (getsockname(socket_, addr, &addr_len))
701 return MapSystemError(errno);
702 if (!address->FromSockAddr(addr, addr_len))
703 return ERR_FAILED;
704
705 return OK;
706}
707
[email protected]7cf40912010-12-09 18:25:03708const BoundNetLog& TCPClientSocketLibevent::NetLog() const {
709 return net_log_;
710}
711
[email protected]9b5614a2010-08-25 20:29:45712void TCPClientSocketLibevent::SetSubresourceSpeculation() {
713 use_history_.set_subresource_speculation();
714}
715
716void TCPClientSocketLibevent::SetOmniboxSpeculation() {
[email protected]62955b792010-09-08 14:00:12717 use_history_.set_omnibox_speculation();
[email protected]9b5614a2010-08-25 20:29:45718}
719
[email protected]0f873e82010-09-02 16:09:01720bool TCPClientSocketLibevent::WasEverUsed() const {
721 return use_history_.was_used_to_convey_data();
722}
723
[email protected]7f7e92392010-10-26 18:29:29724bool TCPClientSocketLibevent::UsingTCPFastOpen() const {
725 return use_tcp_fastopen_;
726}
727
[email protected]5e6efa52011-06-27 17:26:41728int64 TCPClientSocketLibevent::NumBytesRead() const {
729 return num_bytes_read_;
730}
731
732base::TimeDelta TCPClientSocketLibevent::GetConnectTimeMicros() const {
733 return connect_time_micros_;
734}
735
[email protected]36987e92008-09-18 18:46:26736} // namespace net