OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 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 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 return ERR_CONNECTION_TIMED_OUT; | 94 return ERR_CONNECTION_TIMED_OUT; |
95 default: { | 95 default: { |
96 int net_error = MapPosixError(os_error); | 96 int net_error = MapPosixError(os_error); |
97 if (net_error == ERR_FAILED) | 97 if (net_error == ERR_FAILED) |
98 return ERR_CONNECTION_FAILED; // More specific than ERR_FAILED. | 98 return ERR_CONNECTION_FAILED; // More specific than ERR_FAILED. |
99 return net_error; | 99 return net_error; |
100 } | 100 } |
101 } | 101 } |
102 } | 102 } |
103 | 103 |
104 // Given os_error, an errno from a connect() attempt, returns true if | |
105 // connect() should be retried with another address. | |
106 bool ShouldTryNextAddress(int os_error) { | |
107 switch (os_error) { | |
108 case EADDRNOTAVAIL: | |
109 case EAFNOSUPPORT: | |
110 case ECONNREFUSED: | |
111 case ECONNRESET: | |
112 case EACCES: | |
113 case EPERM: | |
114 case ENETUNREACH: | |
115 case EHOSTUNREACH: | |
116 case ENETDOWN: | |
117 case ETIMEDOUT: | |
118 return true; | |
119 default: | |
120 return false; | |
121 } | |
122 } | |
123 | |
124 } // namespace | 104 } // namespace |
125 | 105 |
126 //----------------------------------------------------------------------------- | 106 //----------------------------------------------------------------------------- |
127 | 107 |
128 TCPClientSocketLibevent::TCPClientSocketLibevent(const AddressList& addresses, | 108 TCPClientSocketLibevent::TCPClientSocketLibevent(const AddressList& addresses, |
129 net::NetLog* net_log) | 109 net::NetLog* net_log) |
130 : socket_(kInvalidSocket), | 110 : socket_(kInvalidSocket), |
131 addresses_(addresses), | 111 addresses_(addresses), |
132 current_ai_(addresses_.head()), | 112 current_ai_(NULL), |
133 waiting_connect_(false), | |
134 read_watcher_(this), | 113 read_watcher_(this), |
135 write_watcher_(this), | 114 write_watcher_(this), |
136 read_callback_(NULL), | 115 read_callback_(NULL), |
137 write_callback_(NULL), | 116 write_callback_(NULL), |
| 117 next_connect_state_(CONNECT_STATE_NONE), |
138 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) { | 118 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) { |
139 } | 119 } |
140 | 120 |
141 TCPClientSocketLibevent::~TCPClientSocketLibevent() { | 121 TCPClientSocketLibevent::~TCPClientSocketLibevent() { |
142 Disconnect(); | 122 Disconnect(); |
143 net_log_.AddEvent(NetLog::TYPE_TCP_SOCKET_DONE, NULL); | 123 net_log_.AddEvent(NetLog::TYPE_TCP_SOCKET_DONE, NULL); |
144 } | 124 } |
145 | 125 |
146 int TCPClientSocketLibevent::Connect(CompletionCallback* callback) { | 126 int TCPClientSocketLibevent::Connect(CompletionCallback* callback) { |
147 // If already connected, then just return OK. | 127 // If already connected, then just return OK. |
148 if (socket_ != kInvalidSocket) | 128 if (socket_ != kInvalidSocket) |
149 return OK; | 129 return OK; |
150 | 130 |
151 DCHECK(!waiting_connect_); | 131 DCHECK(!waiting_connect()); |
152 | |
153 TRACE_EVENT_BEGIN("socket.connect", this, ""); | |
154 | 132 |
155 net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT, NULL); | 133 net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT, NULL); |
156 | 134 |
157 int rv = DoConnect(); | 135 // We will try to connect to each address in addresses_. Start with the |
| 136 // first one in the list. |
| 137 next_connect_state_ = CONNECT_STATE_CONNECT; |
| 138 current_ai_ = addresses_.head(); |
158 | 139 |
| 140 int rv = DoConnectLoop(OK); |
159 if (rv == ERR_IO_PENDING) { | 141 if (rv == ERR_IO_PENDING) { |
160 // Synchronous operation not supported. | 142 // Synchronous operation not supported. |
161 DCHECK(callback); | 143 DCHECK(callback); |
162 | |
163 waiting_connect_ = true; | |
164 write_callback_ = callback; | 144 write_callback_ = callback; |
165 } else { | 145 } else { |
166 TRACE_EVENT_END("socket.connect", this, ""); | |
167 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT, NULL); | 146 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT, NULL); |
168 } | 147 } |
169 | 148 |
170 return rv; | 149 return rv; |
171 } | 150 } |
172 | 151 |
| 152 int TCPClientSocketLibevent::DoConnectLoop(int result) { |
| 153 DCHECK_NE(next_connect_state_, CONNECT_STATE_NONE); |
| 154 |
| 155 int rv = result; |
| 156 do { |
| 157 ConnectState state = next_connect_state_; |
| 158 next_connect_state_ = CONNECT_STATE_NONE; |
| 159 switch (state) { |
| 160 case CONNECT_STATE_CONNECT: |
| 161 DCHECK_EQ(OK, rv); |
| 162 rv = DoConnect(); |
| 163 break; |
| 164 case CONNECT_STATE_CONNECT_COMPLETE: |
| 165 rv = DoConnectComplete(rv); |
| 166 break; |
| 167 default: |
| 168 LOG(DFATAL) << "bad state"; |
| 169 rv = ERR_UNEXPECTED; |
| 170 break; |
| 171 } |
| 172 } while (rv != ERR_IO_PENDING && next_connect_state_ != CONNECT_STATE_NONE); |
| 173 |
| 174 return rv; |
| 175 } |
| 176 |
173 int TCPClientSocketLibevent::DoConnect() { | 177 int TCPClientSocketLibevent::DoConnect() { |
174 while (true) { | 178 DCHECK(current_ai_); |
175 DCHECK(current_ai_); | |
176 | 179 |
177 int rv = CreateSocket(current_ai_); | 180 next_connect_state_ = CONNECT_STATE_CONNECT_COMPLETE; |
178 if (rv != OK) | |
179 return rv; | |
180 | 181 |
181 if (!HANDLE_EINTR(connect(socket_, current_ai_->ai_addr, | 182 // Create a non-blocking socket. |
182 static_cast<int>(current_ai_->ai_addrlen)))) { | 183 int os_error = CreateSocket(current_ai_); |
183 // Connected without waiting! | 184 if (os_error) |
184 return OK; | 185 return MapPosixError(os_error); |
185 } | |
186 | 186 |
187 int os_error = errno; | 187 // Connect the socket. |
188 if (os_error == EINPROGRESS) | 188 if (!HANDLE_EINTR(connect(socket_, current_ai_->ai_addr, |
189 break; | 189 static_cast<int>(current_ai_->ai_addrlen)))) { |
190 | 190 // Connected without waiting! |
191 close(socket_); | 191 return OK; |
192 socket_ = kInvalidSocket; | |
193 | |
194 if (current_ai_->ai_next && ShouldTryNextAddress(os_error)) { | |
195 // connect() can fail synchronously for an address even on a | |
196 // non-blocking socket. As an example, this can happen when there is | |
197 // no route to the host. Retry using the next address in the list. | |
198 current_ai_ = current_ai_->ai_next; | |
199 } else { | |
200 DLOG(INFO) << "connect failed: " << os_error; | |
201 return MapConnectError(os_error); | |
202 } | |
203 } | 192 } |
204 | 193 |
205 // Initialize write_socket_watcher_ and link it to our MessagePump. | 194 // Check if the connect() failed synchronously. |
206 // POLLOUT is set if the connection is established. | 195 os_error = errno; |
207 // POLLIN is set if the connection fails. | 196 if (os_error != EINPROGRESS) |
| 197 return MapPosixError(os_error); |
| 198 |
| 199 // Otherwise the connect() is going to complete asynchronously, so watch |
| 200 // for its completion. |
208 if (!MessageLoopForIO::current()->WatchFileDescriptor( | 201 if (!MessageLoopForIO::current()->WatchFileDescriptor( |
209 socket_, true, MessageLoopForIO::WATCH_WRITE, &write_socket_watcher_, | 202 socket_, true, MessageLoopForIO::WATCH_WRITE, &write_socket_watcher_, |
210 &write_watcher_)) { | 203 &write_watcher_)) { |
211 DLOG(INFO) << "WatchFileDescriptor failed: " << errno; | 204 DLOG(INFO) << "WatchFileDescriptor failed: " << errno; |
212 close(socket_); | |
213 socket_ = kInvalidSocket; | |
214 return MapPosixError(errno); | 205 return MapPosixError(errno); |
215 } | 206 } |
216 | 207 |
217 return ERR_IO_PENDING; | 208 return ERR_IO_PENDING; |
218 } | 209 } |
219 | 210 |
| 211 int TCPClientSocketLibevent::DoConnectComplete(int result) { |
| 212 write_socket_watcher_.StopWatchingFileDescriptor(); |
| 213 |
| 214 if (result == OK) |
| 215 return OK; // Done! |
| 216 |
| 217 // Close whatever partially connected socket we currently have. |
| 218 DoDisconnect(); |
| 219 |
| 220 // Try to fall back to the next address in the list. |
| 221 if (current_ai_->ai_next) { |
| 222 next_connect_state_ = CONNECT_STATE_CONNECT; |
| 223 current_ai_ = current_ai_->ai_next; |
| 224 return OK; |
| 225 } |
| 226 |
| 227 // Otherwise there is nothing to fall back to, so give up. |
| 228 return result; |
| 229 } |
| 230 |
220 void TCPClientSocketLibevent::Disconnect() { | 231 void TCPClientSocketLibevent::Disconnect() { |
| 232 DoDisconnect(); |
| 233 current_ai_ = NULL; |
| 234 } |
| 235 |
| 236 void TCPClientSocketLibevent::DoDisconnect() { |
221 if (socket_ == kInvalidSocket) | 237 if (socket_ == kInvalidSocket) |
222 return; | 238 return; |
223 | 239 |
224 TRACE_EVENT_INSTANT("socket.disconnect", this, ""); | |
225 | |
226 bool ok = read_socket_watcher_.StopWatchingFileDescriptor(); | 240 bool ok = read_socket_watcher_.StopWatchingFileDescriptor(); |
227 DCHECK(ok); | 241 DCHECK(ok); |
228 ok = write_socket_watcher_.StopWatchingFileDescriptor(); | 242 ok = write_socket_watcher_.StopWatchingFileDescriptor(); |
229 DCHECK(ok); | 243 DCHECK(ok); |
230 close(socket_); | 244 HANDLE_EINTR(close(socket_)); |
231 socket_ = kInvalidSocket; | 245 socket_ = kInvalidSocket; |
232 waiting_connect_ = false; | |
233 | |
234 // Reset for next time. | |
235 current_ai_ = addresses_.head(); | |
236 } | 246 } |
237 | 247 |
238 bool TCPClientSocketLibevent::IsConnected() const { | 248 bool TCPClientSocketLibevent::IsConnected() const { |
239 if (socket_ == kInvalidSocket || waiting_connect_) | 249 if (socket_ == kInvalidSocket || waiting_connect()) |
240 return false; | 250 return false; |
241 | 251 |
242 // Check if connection is alive. | 252 // Check if connection is alive. |
243 char c; | 253 char c; |
244 int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK)); | 254 int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK)); |
245 if (rv == 0) | 255 if (rv == 0) |
246 return false; | 256 return false; |
247 if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK) | 257 if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK) |
248 return false; | 258 return false; |
249 | 259 |
250 return true; | 260 return true; |
251 } | 261 } |
252 | 262 |
253 bool TCPClientSocketLibevent::IsConnectedAndIdle() const { | 263 bool TCPClientSocketLibevent::IsConnectedAndIdle() const { |
254 if (socket_ == kInvalidSocket || waiting_connect_) | 264 if (socket_ == kInvalidSocket || waiting_connect()) |
255 return false; | 265 return false; |
256 | 266 |
257 // Check if connection is alive and we haven't received any data | 267 // Check if connection is alive and we haven't received any data |
258 // unexpectedly. | 268 // unexpectedly. |
259 char c; | 269 char c; |
260 int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK)); | 270 int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK)); |
261 if (rv >= 0) | 271 if (rv >= 0) |
262 return false; | 272 return false; |
263 if (errno != EAGAIN && errno != EWOULDBLOCK) | 273 if (errno != EAGAIN && errno != EWOULDBLOCK) |
264 return false; | 274 return false; |
265 | 275 |
266 return true; | 276 return true; |
267 } | 277 } |
268 | 278 |
269 int TCPClientSocketLibevent::Read(IOBuffer* buf, | 279 int TCPClientSocketLibevent::Read(IOBuffer* buf, |
270 int buf_len, | 280 int buf_len, |
271 CompletionCallback* callback) { | 281 CompletionCallback* callback) { |
272 DCHECK_NE(kInvalidSocket, socket_); | 282 DCHECK_NE(kInvalidSocket, socket_); |
273 DCHECK(!waiting_connect_); | 283 DCHECK(!waiting_connect()); |
274 DCHECK(!read_callback_); | 284 DCHECK(!read_callback_); |
275 // Synchronous operation not supported | 285 // Synchronous operation not supported |
276 DCHECK(callback); | 286 DCHECK(callback); |
277 DCHECK_GT(buf_len, 0); | 287 DCHECK_GT(buf_len, 0); |
278 | 288 |
279 TRACE_EVENT_BEGIN("socket.read", this, ""); | 289 TRACE_EVENT_BEGIN("socket.read", this, ""); |
280 int nread = HANDLE_EINTR(read(socket_, buf->data(), buf_len)); | 290 int nread = HANDLE_EINTR(read(socket_, buf->data(), buf_len)); |
281 if (nread >= 0) { | 291 if (nread >= 0) { |
282 TRACE_EVENT_END("socket.read", this, StringPrintf("%d bytes", nread)); | 292 TRACE_EVENT_END("socket.read", this, StringPrintf("%d bytes", nread)); |
283 net_log_.AddEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, | 293 net_log_.AddEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, |
(...skipping 15 matching lines...) Expand all Loading... |
299 read_buf_ = buf; | 309 read_buf_ = buf; |
300 read_buf_len_ = buf_len; | 310 read_buf_len_ = buf_len; |
301 read_callback_ = callback; | 311 read_callback_ = callback; |
302 return ERR_IO_PENDING; | 312 return ERR_IO_PENDING; |
303 } | 313 } |
304 | 314 |
305 int TCPClientSocketLibevent::Write(IOBuffer* buf, | 315 int TCPClientSocketLibevent::Write(IOBuffer* buf, |
306 int buf_len, | 316 int buf_len, |
307 CompletionCallback* callback) { | 317 CompletionCallback* callback) { |
308 DCHECK_NE(kInvalidSocket, socket_); | 318 DCHECK_NE(kInvalidSocket, socket_); |
309 DCHECK(!waiting_connect_); | 319 DCHECK(!waiting_connect()); |
310 DCHECK(!write_callback_); | 320 DCHECK(!write_callback_); |
311 // Synchronous operation not supported | 321 // Synchronous operation not supported |
312 DCHECK(callback); | 322 DCHECK(callback); |
313 DCHECK_GT(buf_len, 0); | 323 DCHECK_GT(buf_len, 0); |
314 | 324 |
315 TRACE_EVENT_BEGIN("socket.write", this, ""); | 325 TRACE_EVENT_BEGIN("socket.write", this, ""); |
316 int nwrite = HANDLE_EINTR(write(socket_, buf->data(), buf_len)); | 326 int nwrite = HANDLE_EINTR(write(socket_, buf->data(), buf_len)); |
317 if (nwrite >= 0) { | 327 if (nwrite >= 0) { |
318 TRACE_EVENT_END("socket.write", this, StringPrintf("%d bytes", nwrite)); | 328 TRACE_EVENT_END("socket.write", this, StringPrintf("%d bytes", nwrite)); |
319 net_log_.AddEvent(NetLog::TYPE_SOCKET_BYTES_SENT, | 329 net_log_.AddEvent(NetLog::TYPE_SOCKET_BYTES_SENT, |
320 new NetLogIntegerParameter("num_bytes", nwrite)); | 330 new NetLogIntegerParameter("num_bytes", nwrite)); |
321 return nwrite; | 331 return nwrite; |
322 } | 332 } |
323 if (errno != EAGAIN && errno != EWOULDBLOCK) | 333 if (errno != EAGAIN && errno != EWOULDBLOCK) |
324 return MapPosixError(errno); | 334 return MapPosixError(errno); |
325 | 335 |
326 if (!MessageLoopForIO::current()->WatchFileDescriptor( | 336 if (!MessageLoopForIO::current()->WatchFileDescriptor( |
327 socket_, true, MessageLoopForIO::WATCH_WRITE, | 337 socket_, true, MessageLoopForIO::WATCH_WRITE, |
328 &write_socket_watcher_, &write_watcher_)) { | 338 &write_socket_watcher_, &write_watcher_)) { |
329 DLOG(INFO) << "WatchFileDescriptor failed on write, errno " << errno; | 339 DLOG(INFO) << "WatchFileDescriptor failed on write, errno " << errno; |
330 return MapPosixError(errno); | 340 return MapPosixError(errno); |
331 } | 341 } |
332 | 342 |
333 | |
334 write_buf_ = buf; | 343 write_buf_ = buf; |
335 write_buf_len_ = buf_len; | 344 write_buf_len_ = buf_len; |
336 write_callback_ = callback; | 345 write_callback_ = callback; |
337 return ERR_IO_PENDING; | 346 return ERR_IO_PENDING; |
338 } | 347 } |
339 | 348 |
340 bool TCPClientSocketLibevent::SetReceiveBufferSize(int32 size) { | 349 bool TCPClientSocketLibevent::SetReceiveBufferSize(int32 size) { |
341 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, | 350 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, |
342 reinterpret_cast<const char*>(&size), | 351 reinterpret_cast<const char*>(&size), |
343 sizeof(size)); | 352 sizeof(size)); |
344 DCHECK(!rv) << "Could not set socket receive buffer size: " << errno; | 353 DCHECK(!rv) << "Could not set socket receive buffer size: " << errno; |
345 return rv == 0; | 354 return rv == 0; |
346 } | 355 } |
347 | 356 |
348 bool TCPClientSocketLibevent::SetSendBufferSize(int32 size) { | 357 bool TCPClientSocketLibevent::SetSendBufferSize(int32 size) { |
349 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, | 358 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, |
350 reinterpret_cast<const char*>(&size), | 359 reinterpret_cast<const char*>(&size), |
351 sizeof(size)); | 360 sizeof(size)); |
352 DCHECK(!rv) << "Could not set socket send buffer size: " << errno; | 361 DCHECK(!rv) << "Could not set socket send buffer size: " << errno; |
353 return rv == 0; | 362 return rv == 0; |
354 } | 363 } |
355 | 364 |
356 | 365 |
357 int TCPClientSocketLibevent::CreateSocket(const addrinfo* ai) { | 366 int TCPClientSocketLibevent::CreateSocket(const addrinfo* ai) { |
358 socket_ = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); | 367 socket_ = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
359 if (socket_ == kInvalidSocket) | 368 if (socket_ == kInvalidSocket) |
360 return MapPosixError(errno); | 369 return errno; |
361 | 370 |
362 if (SetNonBlocking(socket_)) { | 371 if (SetNonBlocking(socket_)) { |
363 const int err = MapPosixError(errno); | 372 const int err = errno; |
364 close(socket_); | 373 close(socket_); |
365 socket_ = kInvalidSocket; | 374 socket_ = kInvalidSocket; |
366 return err; | 375 return err; |
367 } | 376 } |
368 | 377 |
369 // This mirrors the behaviour on Windows. See the comment in | 378 // This mirrors the behaviour on Windows. See the comment in |
370 // tcp_client_socket_win.cc after searching for "NODELAY". | 379 // tcp_client_socket_win.cc after searching for "NODELAY". |
371 DisableNagle(socket_); // If DisableNagle fails, we don't care. | 380 DisableNagle(socket_); // If DisableNagle fails, we don't care. |
372 | 381 |
373 return OK; | 382 return 0; |
374 } | 383 } |
375 | 384 |
376 void TCPClientSocketLibevent::DoReadCallback(int rv) { | 385 void TCPClientSocketLibevent::DoReadCallback(int rv) { |
377 DCHECK_NE(rv, ERR_IO_PENDING); | 386 DCHECK_NE(rv, ERR_IO_PENDING); |
378 DCHECK(read_callback_); | 387 DCHECK(read_callback_); |
379 | 388 |
380 // since Run may result in Read being called, clear read_callback_ up front. | 389 // since Run may result in Read being called, clear read_callback_ up front. |
381 CompletionCallback* c = read_callback_; | 390 CompletionCallback* c = read_callback_; |
382 read_callback_ = NULL; | 391 read_callback_ = NULL; |
383 c->Run(rv); | 392 c->Run(rv); |
384 } | 393 } |
385 | 394 |
386 void TCPClientSocketLibevent::DoWriteCallback(int rv) { | 395 void TCPClientSocketLibevent::DoWriteCallback(int rv) { |
387 DCHECK_NE(rv, ERR_IO_PENDING); | 396 DCHECK_NE(rv, ERR_IO_PENDING); |
388 DCHECK(write_callback_); | 397 DCHECK(write_callback_); |
389 | 398 |
390 // since Run may result in Write being called, clear write_callback_ up front. | 399 // since Run may result in Write being called, clear write_callback_ up front. |
391 CompletionCallback* c = write_callback_; | 400 CompletionCallback* c = write_callback_; |
392 write_callback_ = NULL; | 401 write_callback_ = NULL; |
393 c->Run(rv); | 402 c->Run(rv); |
394 } | 403 } |
395 | 404 |
396 void TCPClientSocketLibevent::DidCompleteConnect() { | 405 void TCPClientSocketLibevent::DidCompleteConnect() { |
397 int result = ERR_UNEXPECTED; | 406 DCHECK_EQ(next_connect_state_, CONNECT_STATE_CONNECT_COMPLETE); |
398 | 407 |
399 // Check to see if connect succeeded | 408 // Get the error that connect() completed with. |
400 int os_error = 0; | 409 int os_error = 0; |
401 socklen_t len = sizeof(os_error); | 410 socklen_t len = sizeof(os_error); |
402 if (getsockopt(socket_, SOL_SOCKET, SO_ERROR, &os_error, &len) < 0) | 411 if (getsockopt(socket_, SOL_SOCKET, SO_ERROR, &os_error, &len) < 0) |
403 os_error = errno; | 412 os_error = errno; |
404 | 413 |
| 414 // TODO(eroman): Is this check really necessary? |
405 if (os_error == EINPROGRESS || os_error == EALREADY) { | 415 if (os_error == EINPROGRESS || os_error == EALREADY) { |
406 NOTREACHED(); // This indicates a bug in libevent or our code. | 416 NOTREACHED(); // This indicates a bug in libevent or our code. |
407 result = ERR_IO_PENDING; | 417 return; |
408 } else if (current_ai_->ai_next && ShouldTryNextAddress(os_error)) { | |
409 // This address failed, try next one in list. | |
410 const addrinfo* next = current_ai_->ai_next; | |
411 Disconnect(); | |
412 current_ai_ = next; | |
413 TRACE_EVENT_END("socket.connect", this, ""); | |
414 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT, NULL); | |
415 result = Connect(write_callback_); | |
416 } else { | |
417 result = MapConnectError(os_error); | |
418 bool ok = write_socket_watcher_.StopWatchingFileDescriptor(); | |
419 DCHECK(ok); | |
420 waiting_connect_ = false; | |
421 TRACE_EVENT_END("socket.connect", this, ""); | |
422 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT, NULL); | |
423 } | 418 } |
424 | 419 |
425 if (result != ERR_IO_PENDING) { | 420 int rv = DoConnectLoop(MapConnectError(os_error)); |
426 DoWriteCallback(result); | 421 if (rv != ERR_IO_PENDING) { |
| 422 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT, NULL); |
| 423 DoWriteCallback(rv); |
427 } | 424 } |
428 } | 425 } |
429 | 426 |
430 void TCPClientSocketLibevent::DidCompleteRead() { | 427 void TCPClientSocketLibevent::DidCompleteRead() { |
431 int bytes_transferred; | 428 int bytes_transferred; |
432 bytes_transferred = HANDLE_EINTR(read(socket_, read_buf_->data(), | 429 bytes_transferred = HANDLE_EINTR(read(socket_, read_buf_->data(), |
433 read_buf_len_)); | 430 read_buf_len_)); |
434 | 431 |
435 int result; | 432 int result; |
436 if (bytes_transferred >= 0) { | 433 if (bytes_transferred >= 0) { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
478 | 475 |
479 int TCPClientSocketLibevent::GetPeerAddress(AddressList* address) const { | 476 int TCPClientSocketLibevent::GetPeerAddress(AddressList* address) const { |
480 DCHECK(address); | 477 DCHECK(address); |
481 if (!current_ai_) | 478 if (!current_ai_) |
482 return ERR_UNEXPECTED; | 479 return ERR_UNEXPECTED; |
483 address->Copy(current_ai_, false); | 480 address->Copy(current_ai_, false); |
484 return OK; | 481 return OK; |
485 } | 482 } |
486 | 483 |
487 } // namespace net | 484 } // namespace net |
OLD | NEW |