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

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

Issue 196094: Non-blocking connect() attempts may fail synchronously (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 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
« no previous file with comments | « net/base/host_resolver_proc.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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_client_socket_libevent.h" 5 #include "net/socket/tcp_client_socket_libevent.h"
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 <sys/socket.h> 10 #include <sys/socket.h>
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 71
72 int MapConnectError(int err) { 72 int MapConnectError(int err) {
73 switch (err) { 73 switch (err) {
74 case ETIMEDOUT: 74 case ETIMEDOUT:
75 return ERR_CONNECTION_TIMED_OUT; 75 return ERR_CONNECTION_TIMED_OUT;
76 default: 76 default:
77 return MapPosixError(err); 77 return MapPosixError(err);
78 } 78 }
79 } 79 }
80 80
81 // Given err, an errno from a connect() attempt, returns true if connect()
82 // should be retried with another address.
83 bool ShouldTryNextAddress(int err) {
84 switch (err) {
85 case EADDRNOTAVAIL:
86 case EAFNOSUPPORT:
87 case ECONNREFUSED:
88 case ECONNRESET:
89 case EACCES:
90 case EPERM:
91 case ENETUNREACH:
92 case EHOSTUNREACH:
93 case ENETDOWN:
94 case ETIMEDOUT:
95 return true;
96 default:
97 return false;
98 }
99 }
100
81 } // namespace 101 } // namespace
82 102
83 //----------------------------------------------------------------------------- 103 //-----------------------------------------------------------------------------
84 104
85 TCPClientSocketLibevent::TCPClientSocketLibevent(const AddressList& addresses) 105 TCPClientSocketLibevent::TCPClientSocketLibevent(const AddressList& addresses)
86 : socket_(kInvalidSocket), 106 : socket_(kInvalidSocket),
87 addresses_(addresses), 107 addresses_(addresses),
88 current_ai_(addresses_.head()), 108 current_ai_(addresses_.head()),
89 waiting_connect_(false), 109 waiting_connect_(false),
90 read_watcher_(this), 110 read_watcher_(this),
91 write_watcher_(this), 111 write_watcher_(this),
92 read_callback_(NULL), 112 read_callback_(NULL),
93 write_callback_(NULL) { 113 write_callback_(NULL) {
94 } 114 }
95 115
96 TCPClientSocketLibevent::~TCPClientSocketLibevent() { 116 TCPClientSocketLibevent::~TCPClientSocketLibevent() {
97 Disconnect(); 117 Disconnect();
98 } 118 }
99 119
100 int TCPClientSocketLibevent::Connect(CompletionCallback* callback) { 120 int TCPClientSocketLibevent::Connect(CompletionCallback* callback) {
101 // If already connected, then just return OK. 121 // If already connected, then just return OK.
102 if (socket_ != kInvalidSocket) 122 if (socket_ != kInvalidSocket)
103 return OK; 123 return OK;
104 124
105 DCHECK(!waiting_connect_); 125 DCHECK(!waiting_connect_);
106 126
107 TRACE_EVENT_BEGIN("socket.connect", this, ""); 127 TRACE_EVENT_BEGIN("socket.connect", this, "");
108 const addrinfo* ai = current_ai_;
109 DCHECK(ai);
110 128
111 int rv = CreateSocket(ai); 129 while (true) {
112 if (rv != OK) 130 DCHECK(current_ai_);
113 return rv;
114 131
115 if (!HANDLE_EINTR(connect(socket_, ai->ai_addr, 132 int rv = CreateSocket(current_ai_);
116 static_cast<int>(ai->ai_addrlen)))) { 133 if (rv != OK)
117 TRACE_EVENT_END("socket.connect", this, ""); 134 return rv;
118 // Connected without waiting! 135
119 return OK; 136 if (!HANDLE_EINTR(connect(socket_, current_ai_->ai_addr,
137 static_cast<int>(current_ai_->ai_addrlen)))) {
138 TRACE_EVENT_END("socket.connect", this, "");
139 // Connected without waiting!
140 return OK;
141 }
142
143 int error_code = errno;
144 if (error_code == EINPROGRESS)
145 break;
146
147 close(socket_);
148 socket_ = kInvalidSocket;
149
150 if (current_ai_->ai_next && ShouldTryNextAddress(error_code)) {
151 // connect() can fail synchronously for an address even on a
152 // non-blocking socket. As an example, this can happen when there is
153 // no route to the host. Retry using the next address in the list.
154 current_ai_ = current_ai_->ai_next;
155 } else {
156 DLOG(INFO) << "connect failed: " << error_code;
157 return MapConnectError(error_code);
158 }
120 } 159 }
121 160
122 // Synchronous operation not supported 161 // Synchronous operation not supported
123 DCHECK(callback); 162 DCHECK(callback);
124 163
125 if (errno != EINPROGRESS) {
126 DLOG(INFO) << "connect failed: " << errno;
127 close(socket_);
128 socket_ = kInvalidSocket;
129 return MapConnectError(errno);
130 }
131
132 // Initialize write_socket_watcher_ and link it to our MessagePump. 164 // Initialize write_socket_watcher_ and link it to our MessagePump.
133 // POLLOUT is set if the connection is established. 165 // POLLOUT is set if the connection is established.
134 // POLLIN is set if the connection fails. 166 // POLLIN is set if the connection fails.
135 if (!MessageLoopForIO::current()->WatchFileDescriptor( 167 if (!MessageLoopForIO::current()->WatchFileDescriptor(
136 socket_, true, MessageLoopForIO::WATCH_WRITE, &write_socket_watcher_, 168 socket_, true, MessageLoopForIO::WATCH_WRITE, &write_socket_watcher_,
137 &write_watcher_)) { 169 &write_watcher_)) {
138 DLOG(INFO) << "WatchFileDescriptor failed: " << errno; 170 DLOG(INFO) << "WatchFileDescriptor failed: " << errno;
139 close(socket_); 171 close(socket_);
140 socket_ = kInvalidSocket; 172 socket_ = kInvalidSocket;
141 return MapPosixError(errno); 173 return MapPosixError(errno);
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
317 349
318 // Check to see if connect succeeded 350 // Check to see if connect succeeded
319 int error_code = 0; 351 int error_code = 0;
320 socklen_t len = sizeof(error_code); 352 socklen_t len = sizeof(error_code);
321 if (getsockopt(socket_, SOL_SOCKET, SO_ERROR, &error_code, &len) < 0) 353 if (getsockopt(socket_, SOL_SOCKET, SO_ERROR, &error_code, &len) < 0)
322 error_code = errno; 354 error_code = errno;
323 355
324 if (error_code == EINPROGRESS || error_code == EALREADY) { 356 if (error_code == EINPROGRESS || error_code == EALREADY) {
325 NOTREACHED(); // This indicates a bug in libevent or our code. 357 NOTREACHED(); // This indicates a bug in libevent or our code.
326 result = ERR_IO_PENDING; 358 result = ERR_IO_PENDING;
327 } else if (current_ai_->ai_next && ( 359 } else if (current_ai_->ai_next && ShouldTryNextAddress(error_code)) {
328 error_code == EADDRNOTAVAIL ||
329 error_code == EAFNOSUPPORT ||
330 error_code == ECONNREFUSED ||
331 error_code == ENETUNREACH ||
332 error_code == EHOSTUNREACH ||
333 error_code == ETIMEDOUT)) {
334 // This address failed, try next one in list. 360 // This address failed, try next one in list.
335 const addrinfo* next = current_ai_->ai_next; 361 const addrinfo* next = current_ai_->ai_next;
336 Disconnect(); 362 Disconnect();
337 current_ai_ = next; 363 current_ai_ = next;
338 result = Connect(write_callback_); 364 result = Connect(write_callback_);
339 } else { 365 } else {
340 result = MapConnectError(error_code); 366 result = MapConnectError(error_code);
341 bool ok = write_socket_watcher_.StopWatchingFileDescriptor(); 367 bool ok = write_socket_watcher_.StopWatchingFileDescriptor();
342 DCHECK(ok); 368 DCHECK(ok);
343 waiting_connect_ = false; 369 waiting_connect_ = false;
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 DoWriteCallback(result); 418 DoWriteCallback(result);
393 } 419 }
394 } 420 }
395 421
396 int TCPClientSocketLibevent::GetPeerName(struct sockaddr *name, 422 int TCPClientSocketLibevent::GetPeerName(struct sockaddr *name,
397 socklen_t *namelen) { 423 socklen_t *namelen) {
398 return ::getpeername(socket_, name, namelen); 424 return ::getpeername(socket_, name, namelen);
399 } 425 }
400 426
401 } // namespace net 427 } // namespace net
OLDNEW
« no previous file with comments | « net/base/host_resolver_proc.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698