Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(180)

Side by Side Diff: net/socket/tcp_socket_libevent.cc

Issue 23454010: POSIX only: Move client socket functionality from TCPClientSocket into TCPSocket. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/socket/tcp_socket_libevent.h" 5 #include "net/socket/tcp_socket.h"
wtc 2013/09/13 22:22:44 This should include tcp_socket_libevent.h because
yzshen1 2013/09/13 23:52:40 This is intended, because we need IsTCPFastOpenEna
6 6
7 #include <errno.h> 7 #include <errno.h>
8 #include <fcntl.h> 8 #include <fcntl.h>
9 #include <netdb.h> 9 #include <netdb.h>
10 #include <netinet/tcp.h>
10 #include <sys/socket.h> 11 #include <sys/socket.h>
11 12
12 #include "build/build_config.h" 13 #include "build/build_config.h"
13 14
14 #if defined(OS_POSIX) 15 #if defined(OS_POSIX)
15 #include <netinet/in.h> 16 #include <netinet/in.h>
wtc 2013/09/13 22:22:44 I believe this file can only be used on OS_POSIX.
yzshen1 2013/09/13 23:52:40 Done.
16 #endif 17 #endif
17 18
19 #include "base/callback_helpers.h"
18 #include "base/logging.h" 20 #include "base/logging.h"
21 #include "base/metrics/histogram.h"
22 #include "base/metrics/stats_counters.h"
19 #include "base/posix/eintr_wrapper.h" 23 #include "base/posix/eintr_wrapper.h"
24 #include "net/base/address_list.h"
25 #include "net/base/connection_type_histograms.h"
26 #include "net/base/io_buffer.h"
20 #include "net/base/ip_endpoint.h" 27 #include "net/base/ip_endpoint.h"
21 #include "net/base/net_errors.h" 28 #include "net/base/net_errors.h"
22 #include "net/base/net_util.h" 29 #include "net/base/net_util.h"
23 #include "net/socket/socket_descriptor.h" 30 #include "net/base/network_change_notifier.h"
24 #include "net/socket/socket_net_log_params.h" 31 #include "net/socket/socket_net_log_params.h"
25 32
33 // If we don't have a definition for TCPI_OPT_SYN_DATA, create one.
34 #ifndef TCPI_OPT_SYN_DATA
35 #define TCPI_OPT_SYN_DATA 32
36 #endif
37
26 namespace net { 38 namespace net {
27 39
40 namespace {
41
42 const int kTCPKeepAliveSeconds = 45;
43
44 // SetTCPNoDelay turns on/off buffering in the kernel. By default, TCP sockets
45 // will 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`.
48 bool SetTCPNoDelay(int fd, bool no_delay) {
49 int on = no_delay ? 1 : 0;
50 int error = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
51 return error == 0;
52 }
53
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;
59 return false;
60 }
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;
65 return false;
66 }
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;
70 return false;
71 }
72 #endif
73 return true;
74 }
75
76 int MapConnectError(int os_error) {
77 switch (os_error) {
78 case EACCES:
79 return ERR_NETWORK_ACCESS_DENIED;
80 case ETIMEDOUT:
81 return ERR_CONNECTION_TIMED_OUT;
82 default: {
83 int net_error = MapSystemError(os_error);
84 if (net_error == ERR_FAILED)
85 return ERR_CONNECTION_FAILED; // More specific than ERR_FAILED.
86
87 // Give a more specific error when the user is offline.
88 if (net_error == ERR_ADDRESS_UNREACHABLE &&
89 NetworkChangeNotifier::IsOffline()) {
90 return ERR_INTERNET_DISCONNECTED;
91 }
92 return net_error;
93 }
94 }
95 }
96
97 } // namespace
98
99 //-----------------------------------------------------------------------------
100
101 TCPSocketLibevent::Watcher::Watcher(
102 const base::Closure& read_ready_callback,
103 const base::Closure& write_ready_callback)
104 : read_ready_callback_(read_ready_callback),
105 write_ready_callback_(write_ready_callback) {
106 }
107
108 TCPSocketLibevent::Watcher::~Watcher() {
109 }
110
111 void TCPSocketLibevent::Watcher::OnFileCanReadWithoutBlocking(int /* fd */) {
112 if (!read_ready_callback_.is_null())
113 read_ready_callback_.Run();
wtc 2013/09/13 22:22:44 Do we need to reset read_ready_callback_ and write
yzshen1 2013/09/13 23:52:40 |read_ready_callback_| here is a closure to forwar
114 else
115 NOTREACHED();
116 }
117
118 void TCPSocketLibevent::Watcher::OnFileCanWriteWithoutBlocking(int /* fd */) {
119 if (!write_ready_callback_.is_null())
120 write_ready_callback_.Run();
121 else
122 NOTREACHED();
123 }
124
28 TCPSocketLibevent::TCPSocketLibevent(NetLog* net_log, 125 TCPSocketLibevent::TCPSocketLibevent(NetLog* net_log,
29 const NetLog::Source& source) 126 const NetLog::Source& source)
30 : socket_(kInvalidSocket), 127 : socket_(kInvalidSocket),
128 accept_watcher_(base::Bind(&TCPSocketLibevent::DidCompleteAccept,
129 base::Unretained(this)),
130 base::Closure()),
31 accept_socket_(NULL), 131 accept_socket_(NULL),
32 accept_address_(NULL), 132 accept_address_(NULL),
133 read_watcher_(base::Bind(&TCPSocketLibevent::DidCompleteRead,
134 base::Unretained(this)),
135 base::Closure()),
136 write_watcher_(base::Closure(),
137 base::Bind(&TCPSocketLibevent::DidCompleteConnectOrWrite,
138 base::Unretained(this))),
139 read_buf_len_(0),
140 write_buf_len_(0),
141 use_tcp_fastopen_(IsTCPFastOpenEnabled()),
142 tcp_fastopen_connected_(false),
143 fast_open_status_(FAST_OPEN_STATUS_UNKNOWN),
144 waiting_connect_(false),
145 connect_os_error_(0),
146 logging_multiple_connect_attempts_(false),
33 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) { 147 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
34 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, 148 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
35 source.ToEventParametersCallback()); 149 source.ToEventParametersCallback());
36 } 150 }
37 151
38 TCPSocketLibevent::~TCPSocketLibevent() { 152 TCPSocketLibevent::~TCPSocketLibevent() {
39 if (socket_ != kInvalidSocket)
40 Close();
41 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE); 153 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
154 if (tcp_fastopen_connected_) {
155 UMA_HISTOGRAM_ENUMERATION("Net.TcpFastOpenSocketConnection",
156 fast_open_status_, FAST_OPEN_MAX_VALUE);
157 }
158 Close();
wtc 2013/09/13 22:22:44 It may be better to call Close() before logging ev
yzshen1 2013/09/13 23:52:40 That will reset |tcp_fastopen_connected_| and caus
wtc 2013/09/18 23:26:17 I see. So the original code worked because it neve
yzshen1 2013/09/18 23:40:35 Right. It is never set to false again.
42 } 159 }
43 160
44 int TCPSocketLibevent::Open(AddressFamily family) { 161 int TCPSocketLibevent::Open(AddressFamily family) {
45 DCHECK(CalledOnValidThread()); 162 DCHECK(CalledOnValidThread());
46 DCHECK_EQ(socket_, kInvalidSocket); 163 DCHECK_EQ(socket_, kInvalidSocket);
47 164
48 socket_ = CreatePlatformSocket(ConvertAddressFamily(family), SOCK_STREAM, 165 socket_ = CreatePlatformSocket(ConvertAddressFamily(family), SOCK_STREAM,
49 IPPROTO_TCP); 166 IPPROTO_TCP);
50 if (socket_ < 0) { 167 if (socket_ < 0) {
51 PLOG(ERROR) << "CreatePlatformSocket() returned an error"; 168 PLOG(ERROR) << "CreatePlatformSocket() returned an error";
52 return MapSystemError(errno); 169 return MapSystemError(errno);
53 } 170 }
54 171
55 if (SetNonBlocking(socket_)) { 172 if (SetNonBlocking(socket_)) {
56 int result = MapSystemError(errno); 173 int result = MapSystemError(errno);
57 Close(); 174 Close();
58 return result; 175 return result;
59 } 176 }
60 177
61 return OK; 178 return OK;
62 } 179 }
63 180
64 int TCPSocketLibevent::Adopt(int socket) { 181 int TCPSocketLibevent::AdoptConnectedSocket(int socket,
182 const IPEndPoint& peer_address) {
65 DCHECK(CalledOnValidThread()); 183 DCHECK(CalledOnValidThread());
66 DCHECK_EQ(socket_, kInvalidSocket); 184 DCHECK_EQ(socket_, kInvalidSocket);
67 185
68 socket_ = socket; 186 socket_ = socket;
69 187
70 if (SetNonBlocking(socket_)) { 188 if (SetNonBlocking(socket_)) {
71 int result = MapSystemError(errno); 189 int result = MapSystemError(errno);
72 Close(); 190 Close();
73 return result; 191 return result;
74 } 192 }
75 193
194 peer_address_.reset(new IPEndPoint(peer_address));
195
76 return OK; 196 return OK;
77 } 197 }
78 198
79 int TCPSocketLibevent::Release() {
80 DCHECK(CalledOnValidThread());
81 DCHECK(accept_callback_.is_null());
82
83 int result = socket_;
84 socket_ = kInvalidSocket;
85 return result;
86 }
87
88 int TCPSocketLibevent::Bind(const IPEndPoint& address) { 199 int TCPSocketLibevent::Bind(const IPEndPoint& address) {
89 DCHECK(CalledOnValidThread()); 200 DCHECK(CalledOnValidThread());
90 DCHECK_NE(socket_, kInvalidSocket); 201 DCHECK_NE(socket_, kInvalidSocket);
91 202
92 SockaddrStorage storage; 203 SockaddrStorage storage;
93 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) 204 if (!address.ToSockAddr(storage.addr, &storage.addr_len))
94 return ERR_ADDRESS_INVALID; 205 return ERR_ADDRESS_INVALID;
95 206
96 int result = bind(socket_, storage.addr, storage.addr_len); 207 int result = bind(socket_, storage.addr, storage.addr_len);
97 if (result < 0) { 208 if (result < 0) {
98 PLOG(ERROR) << "bind() returned an error"; 209 PLOG(ERROR) << "bind() returned an error";
99 return MapSystemError(errno); 210 return MapSystemError(errno);
100 } 211 }
101 212
102 return OK; 213 return OK;
103 } 214 }
104 215
105 int TCPSocketLibevent::GetLocalAddress(IPEndPoint* address) const {
106 DCHECK(CalledOnValidThread());
107 DCHECK(address);
108
109 SockaddrStorage storage;
110 if (getsockname(socket_, storage.addr, &storage.addr_len) < 0)
111 return MapSystemError(errno);
112 if (!address->FromSockAddr(storage.addr, storage.addr_len))
113 return ERR_FAILED;
114
115 return OK;
116 }
117
118 int TCPSocketLibevent::Listen(int backlog) { 216 int TCPSocketLibevent::Listen(int backlog) {
119 DCHECK(CalledOnValidThread()); 217 DCHECK(CalledOnValidThread());
120 DCHECK_GT(backlog, 0); 218 DCHECK_GT(backlog, 0);
121 DCHECK_NE(socket_, kInvalidSocket); 219 DCHECK_NE(socket_, kInvalidSocket);
122 220
123 int result = listen(socket_, backlog); 221 int result = listen(socket_, backlog);
124 if (result < 0) { 222 if (result < 0) {
125 PLOG(ERROR) << "listen() returned an error"; 223 PLOG(ERROR) << "listen() returned an error";
126 return MapSystemError(errno); 224 return MapSystemError(errno);
127 } 225 }
(...skipping 10 matching lines...) Expand all
138 DCHECK(!callback.is_null()); 236 DCHECK(!callback.is_null());
139 DCHECK(accept_callback_.is_null()); 237 DCHECK(accept_callback_.is_null());
140 238
141 net_log_.BeginEvent(NetLog::TYPE_TCP_ACCEPT); 239 net_log_.BeginEvent(NetLog::TYPE_TCP_ACCEPT);
142 240
143 int result = AcceptInternal(socket, address); 241 int result = AcceptInternal(socket, address);
144 242
145 if (result == ERR_IO_PENDING) { 243 if (result == ERR_IO_PENDING) {
146 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( 244 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
147 socket_, true, base::MessageLoopForIO::WATCH_READ, 245 socket_, true, base::MessageLoopForIO::WATCH_READ,
148 &accept_socket_watcher_, this)) { 246 &accept_socket_watcher_, &accept_watcher_)) {
149 PLOG(ERROR) << "WatchFileDescriptor failed on read"; 247 PLOG(ERROR) << "WatchFileDescriptor failed on read";
150 return MapSystemError(errno); 248 return MapSystemError(errno);
151 } 249 }
152 250
153 accept_socket_ = socket; 251 accept_socket_ = socket;
154 accept_address_ = address; 252 accept_address_ = address;
155 accept_callback_ = callback; 253 accept_callback_ = callback;
156 } 254 }
157 255
158 return result; 256 return result;
159 } 257 }
160 258
259 int TCPSocketLibevent::Connect(const IPEndPoint& address,
260 const CompletionCallback& callback) {
261 DCHECK(CalledOnValidThread());
262 DCHECK_NE(socket_, kInvalidSocket);
263 DCHECK(!waiting_connect_);
264
265 // |peer_address_| will be non-NULL if Connect() has been called. Unless
266 // Close() is called to reset the internal state, a second call to Connect()
267 // is not allowed.
268 // Please note that we enforce this even if the previous Connect() has
269 // completed and failed. Connecting the same |socket_| again after a
wtc 2013/09/13 22:22:44 Nit: "Please note that we enforce this ... and fai
yzshen1 2013/09/13 23:52:40 I thought this sentence also applies here? Maybe
wtc 2013/09/18 23:26:17 Your comment is fine. Thanks. (Since this won't w
270 // connection attempt failed results in unspecified behavior according to
271 // POSIX.
272 DCHECK(!peer_address_);
273
274 if (!logging_multiple_connect_attempts_)
275 LogConnectBegin(AddressList(address));
276
277 peer_address_.reset(new IPEndPoint(address));
278
279 int rv = DoConnect();
280 if (rv == ERR_IO_PENDING) {
281 // Synchronous operation not supported.
282 DCHECK(!callback.is_null());
283 write_callback_ = callback;
284 waiting_connect_ = true;
285 } else {
286 DoConnectComplete(rv);
287 }
288
289 return rv;
290 }
291
292 bool TCPSocketLibevent::IsConnected() const {
293 DCHECK(CalledOnValidThread());
294
295 if (socket_ == kInvalidSocket || waiting_connect_)
296 return false;
297
298 if (use_tcp_fastopen_ && !tcp_fastopen_connected_ && peer_address_) {
wtc 2013/09/13 22:22:44 Do we need to check peer_address_ in this conditio
yzshen1 2013/09/13 23:52:40 Yes. The following is one example: - |use_tcp_fas
299 // With TCP FastOpen, we pretend that the socket is connected.
300 // This allows GetPeerAddress() to return peer_address_.
301 return true;
302 }
303
304 // Check if connection is alive.
305 char c;
306 int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK));
307 if (rv == 0)
308 return false;
309 if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
310 return false;
311
312 return true;
313 }
314
315 bool TCPSocketLibevent::IsConnectedAndIdle() const {
316 DCHECK(CalledOnValidThread());
317
318 if (socket_ == kInvalidSocket || waiting_connect_)
319 return false;
320
321 // TODO(wtc): should we also handle the TCP FastOpen case here,
322 // as we do in IsConnected()?
323
324 // Check if connection is alive and we haven't received any data
325 // unexpectedly.
326 char c;
327 int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK));
328 if (rv >= 0)
329 return false;
330 if (errno != EAGAIN && errno != EWOULDBLOCK)
331 return false;
332
333 return true;
334 }
335
336 int TCPSocketLibevent::Read(IOBuffer* buf,
337 int buf_len,
338 const CompletionCallback& callback) {
339 DCHECK(CalledOnValidThread());
340 DCHECK_NE(kInvalidSocket, socket_);
341 DCHECK(!waiting_connect_);
342 DCHECK(read_callback_.is_null());
343 // Synchronous operation not supported
344 DCHECK(!callback.is_null());
345 DCHECK_GT(buf_len, 0);
346
347 int nread = HANDLE_EINTR(read(socket_, buf->data(), buf_len));
348 if (nread >= 0) {
349 base::StatsCounter read_bytes("tcp.read_bytes");
350 read_bytes.Add(nread);
351 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, nread,
352 buf->data());
353 RecordFastOpenStatus();
354 return nread;
355 }
356 if (errno != EAGAIN && errno != EWOULDBLOCK) {
357 int net_error = MapSystemError(errno);
358 net_log_.AddEvent(NetLog::TYPE_SOCKET_READ_ERROR,
359 CreateNetLogSocketErrorCallback(net_error, errno));
360 return net_error;
361 }
362
363 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
364 socket_, true, base::MessageLoopForIO::WATCH_READ,
365 &read_socket_watcher_, &read_watcher_)) {
366 DVLOG(1) << "WatchFileDescriptor failed on read, errno " << errno;
367 return MapSystemError(errno);
368 }
369
370 read_buf_ = buf;
371 read_buf_len_ = buf_len;
372 read_callback_ = callback;
373 return ERR_IO_PENDING;
374 }
375
376 int TCPSocketLibevent::Write(IOBuffer* buf,
377 int buf_len,
378 const CompletionCallback& callback) {
379 DCHECK(CalledOnValidThread());
380 DCHECK_NE(kInvalidSocket, socket_);
381 DCHECK(!waiting_connect_);
382 DCHECK(write_callback_.is_null());
383 // Synchronous operation not supported
384 DCHECK(!callback.is_null());
385 DCHECK_GT(buf_len, 0);
386
387 int nwrite = InternalWrite(buf, buf_len);
388 if (nwrite >= 0) {
389 base::StatsCounter write_bytes("tcp.write_bytes");
390 write_bytes.Add(nwrite);
391 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, nwrite,
392 buf->data());
393 return nwrite;
394 }
395 if (errno != EAGAIN && errno != EWOULDBLOCK) {
396 int net_error = MapSystemError(errno);
397 net_log_.AddEvent(NetLog::TYPE_SOCKET_WRITE_ERROR,
398 CreateNetLogSocketErrorCallback(net_error, errno));
399 return net_error;
400 }
401
402 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
403 socket_, true, base::MessageLoopForIO::WATCH_WRITE,
404 &write_socket_watcher_, &write_watcher_)) {
405 DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno;
406 return MapSystemError(errno);
407 }
408
409 write_buf_ = buf;
410 write_buf_len_ = buf_len;
411 write_callback_ = callback;
412 return ERR_IO_PENDING;
413 }
414
415 int TCPSocketLibevent::GetLocalAddress(IPEndPoint* address) const {
416 DCHECK(CalledOnValidThread());
417 DCHECK(address);
wtc 2013/09/13 22:22:44 We probably should do if (socket_ == kInvalidSoc
yzshen1 2013/09/13 23:52:40 IMHO, ERR_SOCKET_NOT_CONNECTED is not accurate. Fo
wtc 2013/09/18 23:26:17 Yes, this is fine. If socket_ is kInvalidSocket (
418
419 SockaddrStorage storage;
420 if (getsockname(socket_, storage.addr, &storage.addr_len) < 0)
421 return MapSystemError(errno);
422 if (!address->FromSockAddr(storage.addr, storage.addr_len))
423 return ERR_FAILED;
wtc 2013/09/13 22:22:44 Please use a better error code. (You fixed this in
yzshen1 2013/09/13 23:52:40 Done. I used ERR_ADDRESS_INVALID.
424
425 return OK;
426 }
427
428 int TCPSocketLibevent::GetPeerAddress(IPEndPoint* address) const {
429 DCHECK(CalledOnValidThread());
430 DCHECK(address);
431 if (!IsConnected())
432 return ERR_SOCKET_NOT_CONNECTED;
433 *address = *peer_address_;
434 return OK;
435 }
436
161 int TCPSocketLibevent::SetDefaultOptionsForServer() { 437 int TCPSocketLibevent::SetDefaultOptionsForServer() {
438 DCHECK(CalledOnValidThread());
162 return SetAddressReuse(true); 439 return SetAddressReuse(true);
163 } 440 }
164 441
442 void TCPSocketLibevent::SetDefaultOptionsForClient() {
443 DCHECK(CalledOnValidThread());
444
445 // This mirrors the behaviour on Windows. See the comment in
446 // tcp_socket_win.cc after searching for "NODELAY".
447 SetTCPNoDelay(socket_, true); // If SetTCPNoDelay fails, we don't care.
448 SetTCPKeepAlive(socket_, true, kTCPKeepAliveSeconds);
449 }
450
165 int TCPSocketLibevent::SetAddressReuse(bool allow) { 451 int TCPSocketLibevent::SetAddressReuse(bool allow) {
452 DCHECK(CalledOnValidThread());
453
166 // SO_REUSEADDR is useful for server sockets to bind to a recently unbound 454 // SO_REUSEADDR is useful for server sockets to bind to a recently unbound
167 // port. When a socket is closed, the end point changes its state to TIME_WAIT 455 // port. When a socket is closed, the end point changes its state to TIME_WAIT
168 // and wait for 2 MSL (maximum segment lifetime) to ensure the remote peer 456 // and wait for 2 MSL (maximum segment lifetime) to ensure the remote peer
169 // acknowledges its closure. For server sockets, it is usually safe to 457 // acknowledges its closure. For server sockets, it is usually safe to
170 // bind to a TIME_WAIT end point immediately, which is a widely adopted 458 // bind to a TIME_WAIT end point immediately, which is a widely adopted
171 // behavior. 459 // behavior.
172 // 460 //
173 // Note that on *nix, SO_REUSEADDR does not enable the TCP socket to bind to 461 // Note that on *nix, SO_REUSEADDR does not enable the TCP socket to bind to
174 // an end point that is already bound by another socket. To do that one must 462 // an end point that is already bound by another socket. To do that one must
175 // set SO_REUSEPORT instead. This option is not provided on Linux prior 463 // set SO_REUSEPORT instead. This option is not provided on Linux prior
176 // to 3.9. 464 // to 3.9.
177 // 465 //
178 // SO_REUSEPORT is provided in MacOS X and iOS. 466 // SO_REUSEPORT is provided in MacOS X and iOS.
179 int boolean_value = allow ? 1 : 0; 467 int boolean_value = allow ? 1 : 0;
180 int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &boolean_value, 468 int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &boolean_value,
181 sizeof(boolean_value)); 469 sizeof(boolean_value));
182 if (rv < 0) 470 if (rv < 0)
183 return MapSystemError(errno); 471 return MapSystemError(errno);
184 return OK; 472 return OK;
185 } 473 }
186 474
475 bool TCPSocketLibevent::SetReceiveBufferSize(int32 size) {
476 DCHECK(CalledOnValidThread());
477 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF,
478 reinterpret_cast<const char*>(&size),
479 sizeof(size));
480 DCHECK(!rv) << "Could not set socket receive buffer size: " << errno;
481 return rv == 0;
482 }
483
484 bool TCPSocketLibevent::SetSendBufferSize(int32 size) {
485 DCHECK(CalledOnValidThread());
486 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
487 reinterpret_cast<const char*>(&size),
488 sizeof(size));
489 DCHECK(!rv) << "Could not set socket send buffer size: " << errno;
490 return rv == 0;
491 }
492
493 bool TCPSocketLibevent::SetKeepAlive(bool enable, int delay) {
494 DCHECK(CalledOnValidThread());
495 return SetTCPKeepAlive(socket_, enable, delay);
496 }
497
498 bool TCPSocketLibevent::SetNoDelay(bool no_delay) {
499 DCHECK(CalledOnValidThread());
500 return SetTCPNoDelay(socket_, no_delay);
501 }
502
187 void TCPSocketLibevent::Close() { 503 void TCPSocketLibevent::Close() {
504 DCHECK(CalledOnValidThread());
505
188 if (socket_ != kInvalidSocket) { 506 if (socket_ != kInvalidSocket) {
189 bool ok = accept_socket_watcher_.StopWatchingFileDescriptor();
190 DCHECK(ok);
191 if (HANDLE_EINTR(close(socket_)) < 0) 507 if (HANDLE_EINTR(close(socket_)) < 0)
192 PLOG(ERROR) << "close"; 508 PLOG(ERROR) << "close";
193 socket_ = kInvalidSocket; 509 socket_ = kInvalidSocket;
194 } 510 }
511
512 bool ok = accept_socket_watcher_.StopWatchingFileDescriptor();
513 DCHECK(ok);
514 ok = read_socket_watcher_.StopWatchingFileDescriptor();
515 DCHECK(ok);
516 ok = write_socket_watcher_.StopWatchingFileDescriptor();
517 DCHECK(ok);
518
519 if (!accept_callback_.is_null()) {
520 accept_socket_ = NULL;
521 accept_address_ = NULL;
522 accept_callback_.Reset();
523 }
524
525 if (!read_callback_.is_null()) {
526 read_buf_ = NULL;
527 read_buf_len_ = 0;
528 read_callback_.Reset();
529 }
530
531 if (!write_callback_.is_null()) {
532 write_buf_ = NULL;
533 write_buf_len_ = 0;
534 write_callback_.Reset();
535 }
536
537 tcp_fastopen_connected_ = false;
538 fast_open_status_ = FAST_OPEN_STATUS_UNKNOWN;
539 waiting_connect_ = false;
540 peer_address_.reset();
541 connect_os_error_ = 0;
542 }
543
544 bool TCPSocketLibevent::UsingTCPFastOpen() const {
545 return use_tcp_fastopen_;
546 }
547
548 void TCPSocketLibevent::StartLoggingMultipleConnectAttempts(
549 const AddressList& addresses) {
550 if (!logging_multiple_connect_attempts_) {
551 logging_multiple_connect_attempts_ = true;
552 LogConnectBegin(addresses);
553 } else {
554 NOTREACHED();
555 }
556 }
557
558 void TCPSocketLibevent::EndLoggingMultipleConnectAttempts(int net_error) {
559 if (logging_multiple_connect_attempts_) {
560 LogConnectEnd(net_error);
561 logging_multiple_connect_attempts_ = false;
562 } else {
563 NOTREACHED();
564 }
195 } 565 }
196 566
197 int TCPSocketLibevent::AcceptInternal(scoped_ptr<TCPSocketLibevent>* socket, 567 int TCPSocketLibevent::AcceptInternal(scoped_ptr<TCPSocketLibevent>* socket,
198 IPEndPoint* address) { 568 IPEndPoint* address) {
199 SockaddrStorage storage; 569 SockaddrStorage storage;
200 int new_socket = HANDLE_EINTR(accept(socket_, 570 int new_socket = HANDLE_EINTR(accept(socket_,
201 storage.addr, 571 storage.addr,
202 &storage.addr_len)); 572 &storage.addr_len));
203 if (new_socket < 0) { 573 if (new_socket < 0) {
204 int net_error = MapSystemError(errno); 574 int net_error = MapSystemError(errno);
205 if (net_error != ERR_IO_PENDING) 575 if (net_error != ERR_IO_PENDING)
206 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, net_error); 576 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, net_error);
207 return net_error; 577 return net_error;
208 } 578 }
209 579
210 IPEndPoint ip_end_point; 580 IPEndPoint ip_end_point;
211 if (!ip_end_point.FromSockAddr(storage.addr, storage.addr_len)) { 581 if (!ip_end_point.FromSockAddr(storage.addr, storage.addr_len)) {
212 NOTREACHED(); 582 NOTREACHED();
213 if (HANDLE_EINTR(close(new_socket)) < 0) 583 if (HANDLE_EINTR(close(new_socket)) < 0)
214 PLOG(ERROR) << "close"; 584 PLOG(ERROR) << "close";
215 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, ERR_FAILED); 585 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, ERR_FAILED);
216 return ERR_FAILED; 586 return ERR_FAILED;
wtc 2013/09/13 22:22:44 Use a better error code (on lines 585 and 586).
yzshen1 2013/09/13 23:52:40 I changed to ERR_ADDRESS_INVALID. Does it sound ok
wtc 2013/09/18 23:26:17 Yes. Since this failure is unlikely (note the NOTR
217 } 587 }
218 scoped_ptr<TCPSocketLibevent> tcp_socket(new TCPSocketLibevent( 588 scoped_ptr<TCPSocketLibevent> tcp_socket(new TCPSocketLibevent(
219 net_log_.net_log(), net_log_.source())); 589 net_log_.net_log(), net_log_.source()));
220 int adopt_result = tcp_socket->Adopt(new_socket); 590 int adopt_result = tcp_socket->AdoptConnectedSocket(new_socket, ip_end_point);
221 if (adopt_result != OK) { 591 if (adopt_result != OK) {
222 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, adopt_result); 592 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, adopt_result);
223 return adopt_result; 593 return adopt_result;
224 } 594 }
225 *socket = tcp_socket.Pass(); 595 *socket = tcp_socket.Pass();
226 *address = ip_end_point; 596 *address = ip_end_point;
227 net_log_.EndEvent(NetLog::TYPE_TCP_ACCEPT, 597 net_log_.EndEvent(NetLog::TYPE_TCP_ACCEPT,
228 CreateNetLogIPEndPointCallback(&ip_end_point)); 598 CreateNetLogIPEndPointCallback(&ip_end_point));
229 return OK; 599 return OK;
230 } 600 }
231 601
232 void TCPSocketLibevent::OnFileCanReadWithoutBlocking(int fd) { 602 int TCPSocketLibevent::DoConnect() {
603 DCHECK_EQ(0, connect_os_error_);
604
605 net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT,
606 CreateNetLogIPEndPointCallback(peer_address_.get()));
607
608 // Connect the socket.
609 if (!use_tcp_fastopen_) {
610 SockaddrStorage storage;
611 if (!peer_address_->ToSockAddr(storage.addr, &storage.addr_len))
612 return ERR_INVALID_ARGUMENT;
613
614 if (!HANDLE_EINTR(connect(socket_, storage.addr, storage.addr_len))) {
615 // Connected without waiting!
616 return OK;
617 }
618 } else {
619 // With TCP FastOpen, we pretend that the socket is connected.
620 DCHECK(!tcp_fastopen_connected_);
621 return OK;
622 }
623
624 // Check if the connect() failed synchronously.
625 connect_os_error_ = errno;
626 if (connect_os_error_ != EINPROGRESS)
627 return MapConnectError(connect_os_error_);
628
629 // Otherwise the connect() is going to complete asynchronously, so watch
630 // for its completion.
631 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
632 socket_, true, base::MessageLoopForIO::WATCH_WRITE,
633 &write_socket_watcher_, &write_watcher_)) {
634 connect_os_error_ = errno;
635 DVLOG(1) << "WatchFileDescriptor failed: " << connect_os_error_;
636 return MapSystemError(connect_os_error_);
637 }
638
639 return ERR_IO_PENDING;
640 }
641
642 void TCPSocketLibevent::DoConnectComplete(int result) {
643 // Log the end of this attempt (and any OS error it threw).
644 int os_error = connect_os_error_;
645 connect_os_error_ = 0;
646 if (result != OK) {
647 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT,
648 NetLog::IntegerCallback("os_error", os_error));
649 } else {
650 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT);
651 }
652
653 if (!logging_multiple_connect_attempts_)
654 LogConnectEnd(result);
655 }
656
657 void TCPSocketLibevent::LogConnectBegin(const AddressList& addresses) {
658 base::StatsCounter connects("tcp.connect");
659 connects.Increment();
660
661 net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT,
662 addresses.CreateNetLogCallback());
663 }
664
665 void TCPSocketLibevent::LogConnectEnd(int net_error) {
666 if (net_error == OK)
667 UpdateConnectionTypeHistograms(CONNECTION_ANY);
668
669 if (net_error != OK) {
670 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT, net_error);
671 return;
672 }
673
674 SockaddrStorage storage;
675 int rv = getsockname(socket_, storage.addr, &storage.addr_len);
676 if (rv != 0) {
677 PLOG(ERROR) << "getsockname() [rv: " << rv << "] error: ";
678 NOTREACHED();
679 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT, rv);
680 return;
681 }
682
683 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT,
684 CreateNetLogSourceAddressCallback(storage.addr,
685 storage.addr_len));
686 }
687
688 void TCPSocketLibevent::DidCompleteRead() {
689 RecordFastOpenStatus();
690 if (read_callback_.is_null())
wtc 2013/09/13 22:22:44 Do you know why read_callback_ can be null? (I kno
yzshen1 2013/09/13 23:52:40 I don't know any scenario in which read_callback_
wtc 2013/09/18 23:26:17 No change needed. I was just curious if you unders
691 return;
692
693 int bytes_transferred;
694 bytes_transferred = HANDLE_EINTR(read(socket_, read_buf_->data(),
695 read_buf_len_));
696
697 int result;
698 if (bytes_transferred >= 0) {
699 result = bytes_transferred;
700 base::StatsCounter read_bytes("tcp.read_bytes");
701 read_bytes.Add(bytes_transferred);
702 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, result,
703 read_buf_->data());
704 } else {
705 result = MapSystemError(errno);
706 if (result != ERR_IO_PENDING) {
707 net_log_.AddEvent(NetLog::TYPE_SOCKET_READ_ERROR,
708 CreateNetLogSocketErrorCallback(result, errno));
709 }
710 }
711
712 if (result != ERR_IO_PENDING) {
713 read_buf_ = NULL;
714 read_buf_len_ = 0;
715 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
716 DCHECK(ok);
717 base::ResetAndReturn(&read_callback_).Run(result);
718 }
719 }
720
721 void TCPSocketLibevent::DidCompleteWrite() {
722 DCHECK(!write_callback_.is_null());
723
724 int bytes_transferred;
725 bytes_transferred = HANDLE_EINTR(write(socket_, write_buf_->data(),
726 write_buf_len_));
727
728 int result;
729 if (bytes_transferred >= 0) {
730 result = bytes_transferred;
731 base::StatsCounter write_bytes("tcp.write_bytes");
732 write_bytes.Add(bytes_transferred);
733 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, result,
734 write_buf_->data());
735 } else {
736 result = MapSystemError(errno);
737 if (result != ERR_IO_PENDING) {
738 net_log_.AddEvent(NetLog::TYPE_SOCKET_WRITE_ERROR,
739 CreateNetLogSocketErrorCallback(result, errno));
740 }
741 }
742
743 if (result != ERR_IO_PENDING) {
744 write_buf_ = NULL;
745 write_buf_len_ = 0;
746 write_socket_watcher_.StopWatchingFileDescriptor();
747 base::ResetAndReturn(&write_callback_).Run(result);
748 }
749 }
750
751 void TCPSocketLibevent::DidCompleteConnect() {
752 DCHECK(waiting_connect_);
753
754 // Get the error that connect() completed with.
755 int os_error = 0;
756 socklen_t len = sizeof(os_error);
757 if (getsockopt(socket_, SOL_SOCKET, SO_ERROR, &os_error, &len) < 0)
758 os_error = errno;
759
760 int result = OK;
761 // TODO(eroman): Is this check really necessary?
762 if (os_error == EINPROGRESS || os_error == EALREADY) {
wtc 2013/09/13 22:22:44 Let's remove this check and the TODO comment. EIN
yzshen1 2013/09/13 23:52:40 Done.
763 NOTREACHED(); // This indicates a bug in libevent or our code.
764 result = ERR_UNEXPECTED;
765 } else {
766 result = MapConnectError(os_error);
767 }
768
769 connect_os_error_ = os_error;
770 if (result != ERR_IO_PENDING) {
771 DoConnectComplete(result);
772 waiting_connect_ = false;
773 write_socket_watcher_.StopWatchingFileDescriptor();
774 base::ResetAndReturn(&write_callback_).Run(result);
775 }
776 }
777
778 void TCPSocketLibevent::DidCompleteConnectOrWrite() {
779 if (waiting_connect_) {
780 DidCompleteConnect();
781 } else if (!write_callback_.is_null()) {
wtc 2013/09/13 22:22:44 (I know this is_null() check comes from the origin
yzshen1 2013/09/13 23:52:40 Done.
782 DidCompleteWrite();
783 }
784 }
785
786 void TCPSocketLibevent::DidCompleteAccept() {
233 DCHECK(CalledOnValidThread()); 787 DCHECK(CalledOnValidThread());
234 788
235 int result = AcceptInternal(accept_socket_, accept_address_); 789 int result = AcceptInternal(accept_socket_, accept_address_);
236 if (result != ERR_IO_PENDING) { 790 if (result != ERR_IO_PENDING) {
237 accept_socket_ = NULL; 791 accept_socket_ = NULL;
238 accept_address_ = NULL; 792 accept_address_ = NULL;
239 bool ok = accept_socket_watcher_.StopWatchingFileDescriptor(); 793 bool ok = accept_socket_watcher_.StopWatchingFileDescriptor();
240 DCHECK(ok); 794 DCHECK(ok);
241 CompletionCallback callback = accept_callback_; 795 CompletionCallback callback = accept_callback_;
242 accept_callback_.Reset(); 796 accept_callback_.Reset();
243 callback.Run(result); 797 callback.Run(result);
244 } 798 }
245 } 799 }
246 800
247 void TCPSocketLibevent::OnFileCanWriteWithoutBlocking(int fd) { 801 int TCPSocketLibevent::InternalWrite(IOBuffer* buf, int buf_len) {
248 NOTREACHED(); 802 int nwrite;
803 if (use_tcp_fastopen_ && !tcp_fastopen_connected_) {
804 SockaddrStorage storage;
805 if (!peer_address_->ToSockAddr(storage.addr, &storage.addr_len)) {
806 errno = EINVAL;
807 return -1;
808 }
809
810 int flags = 0x20000000; // Magic flag to enable TCP_FASTOPEN.
811 #if defined(OS_LINUX)
812 // sendto() will fail with EPIPE when the system doesn't support TCP Fast
813 // Open. Theoretically that shouldn't happen since the caller should check
814 // for system support on startup, but users may dynamically disable TCP Fast
815 // Open via sysctl.
816 flags |= MSG_NOSIGNAL;
817 #endif // defined(OS_LINUX)
818 nwrite = HANDLE_EINTR(sendto(socket_,
819 buf->data(),
820 buf_len,
821 flags,
822 storage.addr,
823 storage.addr_len));
824 tcp_fastopen_connected_ = true;
825
826 if (nwrite < 0) {
827 DCHECK_NE(EPIPE, errno);
828
829 // If errno == EINPROGRESS, that means the kernel didn't have a cookie
830 // and would block. The kernel is internally doing a connect() though.
831 // Remap EINPROGRESS to EAGAIN so we treat this the same as our other
832 // asynchronous cases. Note that the user buffer has not been copied to
833 // kernel space.
834 if (errno == EINPROGRESS) {
835 errno = EAGAIN;
836 fast_open_status_ = FAST_OPEN_SLOW_CONNECT_RETURN;
837 } else {
838 fast_open_status_ = FAST_OPEN_ERROR;
839 }
840 } else {
841 fast_open_status_ = FAST_OPEN_FAST_CONNECT_RETURN;
842 }
843 } else {
844 nwrite = HANDLE_EINTR(write(socket_, buf->data(), buf_len));
845 }
846 return nwrite;
847 }
848
849 void TCPSocketLibevent::RecordFastOpenStatus() {
850 if (use_tcp_fastopen_ &&
851 (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN ||
852 fast_open_status_ == FAST_OPEN_SLOW_CONNECT_RETURN)) {
853 DCHECK_NE(FAST_OPEN_STATUS_UNKNOWN, fast_open_status_);
854 bool getsockopt_success(false);
855 bool server_acked_data(false);
856 #if defined(TCP_INFO)
857 // Probe to see the if the socket used TCP Fast Open.
858 tcp_info info;
859 socklen_t info_len = sizeof(tcp_info);
860 getsockopt_success =
861 getsockopt(socket_, IPPROTO_TCP, TCP_INFO, &info, &info_len) == 0 &&
862 info_len == sizeof(tcp_info);
863 server_acked_data = getsockopt_success &&
864 (info.tcpi_options & TCPI_OPT_SYN_DATA);
865 #endif
866 if (getsockopt_success) {
867 if (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN) {
868 fast_open_status_ = (server_acked_data ? FAST_OPEN_SYN_DATA_ACK :
869 FAST_OPEN_SYN_DATA_NACK);
870 } else {
871 fast_open_status_ = (server_acked_data ? FAST_OPEN_NO_SYN_DATA_ACK :
872 FAST_OPEN_NO_SYN_DATA_NACK);
873 }
874 } else {
875 fast_open_status_ = (fast_open_status_ == FAST_OPEN_FAST_CONNECT_RETURN ?
876 FAST_OPEN_SYN_DATA_FAILED :
877 FAST_OPEN_NO_SYN_DATA_FAILED);
878 }
879 }
249 } 880 }
250 881
251 } // namespace net 882 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698