| 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 |