| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/base/tcp_client_socket_win.h" | |
| 6 | |
| 7 #include "base/basictypes.h" | |
| 8 #include "base/compiler_specific.h" | |
| 9 #include "base/memory_debug.h" | |
| 10 #include "base/string_util.h" | |
| 11 #include "base/sys_info.h" | |
| 12 #include "base/trace_event.h" | |
| 13 #include "net/base/io_buffer.h" | |
| 14 #include "net/base/net_errors.h" | |
| 15 #include "net/base/winsock_init.h" | |
| 16 | |
| 17 namespace net { | |
| 18 | |
| 19 namespace { | |
| 20 | |
| 21 // If the (manual-reset) event object is signaled, resets it and returns true. | |
| 22 // Otherwise, does nothing and returns false. Called after a Winsock function | |
| 23 // succeeds synchronously | |
| 24 // | |
| 25 // Our testing shows that except in rare cases (when running inside QEMU), | |
| 26 // the event object is already signaled at this point, so we call this method | |
| 27 // to avoid a context switch in common cases. This is just a performance | |
| 28 // optimization. The code still works if this function simply returns false. | |
| 29 bool ResetEventIfSignaled(WSAEVENT hEvent) { | |
| 30 // TODO(wtc): Remove the CHECKs after enough testing. | |
| 31 DWORD wait_rv = WaitForSingleObject(hEvent, 0); | |
| 32 if (wait_rv == WAIT_TIMEOUT) | |
| 33 return false; // The event object is not signaled. | |
| 34 CHECK(wait_rv == WAIT_OBJECT_0); | |
| 35 BOOL ok = WSAResetEvent(hEvent); | |
| 36 CHECK(ok); | |
| 37 return true; | |
| 38 } | |
| 39 | |
| 40 //----------------------------------------------------------------------------- | |
| 41 | |
| 42 int MapWinsockError(DWORD err) { | |
| 43 // There are numerous Winsock error codes, but these are the ones we thus far | |
| 44 // find interesting. | |
| 45 switch (err) { | |
| 46 case WSAENETDOWN: | |
| 47 return ERR_INTERNET_DISCONNECTED; | |
| 48 case WSAETIMEDOUT: | |
| 49 return ERR_TIMED_OUT; | |
| 50 case WSAECONNRESET: | |
| 51 case WSAENETRESET: // Related to keep-alive | |
| 52 return ERR_CONNECTION_RESET; | |
| 53 case WSAECONNABORTED: | |
| 54 return ERR_CONNECTION_ABORTED; | |
| 55 case WSAECONNREFUSED: | |
| 56 return ERR_CONNECTION_REFUSED; | |
| 57 case WSAEDISCON: | |
| 58 // Returned by WSARecv or WSARecvFrom for message-oriented sockets (where | |
| 59 // a return value of zero means a zero-byte message) to indicate graceful | |
| 60 // connection shutdown. We should not ever see this error code for TCP | |
| 61 // sockets, which are byte stream oriented. | |
| 62 NOTREACHED(); | |
| 63 return ERR_CONNECTION_CLOSED; | |
| 64 case WSAEHOSTUNREACH: | |
| 65 case WSAENETUNREACH: | |
| 66 return ERR_ADDRESS_UNREACHABLE; | |
| 67 case WSAEADDRNOTAVAIL: | |
| 68 return ERR_ADDRESS_INVALID; | |
| 69 case WSA_IO_INCOMPLETE: | |
| 70 return ERR_UNEXPECTED; | |
| 71 case ERROR_SUCCESS: | |
| 72 return OK; | |
| 73 default: | |
| 74 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; | |
| 75 return ERR_FAILED; | |
| 76 } | |
| 77 } | |
| 78 | |
| 79 } // namespace | |
| 80 | |
| 81 //----------------------------------------------------------------------------- | |
| 82 | |
| 83 // This class encapsulates all the state that has to be preserved as long as | |
| 84 // there is a network IO operation in progress. If the owner TCPClientSocketWin | |
| 85 // is destroyed while an operation is in progress, the Core is detached and it | |
| 86 // lives until the operation completes and the OS doesn't reference any resource | |
| 87 // declared on this class anymore. | |
| 88 class TCPClientSocketWin::Core : public base::RefCounted<Core> { | |
| 89 public: | |
| 90 explicit Core(TCPClientSocketWin* socket); | |
| 91 ~Core(); | |
| 92 | |
| 93 // Start watching for the end of a read or write operation. | |
| 94 void WatchForRead(); | |
| 95 void WatchForWrite(); | |
| 96 | |
| 97 // The TCPClientSocketWin is going away. | |
| 98 void Detach() { socket_ = NULL; } | |
| 99 | |
| 100 // The separate OVERLAPPED variables for asynchronous operation. | |
| 101 // |read_overlapped_| is used for both Connect() and Read(). | |
| 102 // |write_overlapped_| is only used for Write(); | |
| 103 OVERLAPPED read_overlapped_; | |
| 104 OVERLAPPED write_overlapped_; | |
| 105 | |
| 106 // The buffers used in Read() and Write(). | |
| 107 WSABUF read_buffer_; | |
| 108 WSABUF write_buffer_; | |
| 109 scoped_refptr<IOBuffer> read_iobuffer_; | |
| 110 scoped_refptr<IOBuffer> write_iobuffer_; | |
| 111 | |
| 112 private: | |
| 113 class ReadDelegate : public base::ObjectWatcher::Delegate { | |
| 114 public: | |
| 115 explicit ReadDelegate(Core* core) : core_(core) {} | |
| 116 virtual ~ReadDelegate() {} | |
| 117 | |
| 118 // base::ObjectWatcher::Delegate methods: | |
| 119 virtual void OnObjectSignaled(HANDLE object); | |
| 120 | |
| 121 private: | |
| 122 Core* const core_; | |
| 123 }; | |
| 124 | |
| 125 class WriteDelegate : public base::ObjectWatcher::Delegate { | |
| 126 public: | |
| 127 explicit WriteDelegate(Core* core) : core_(core) {} | |
| 128 virtual ~WriteDelegate() {} | |
| 129 | |
| 130 // base::ObjectWatcher::Delegate methods: | |
| 131 virtual void OnObjectSignaled(HANDLE object); | |
| 132 | |
| 133 private: | |
| 134 Core* const core_; | |
| 135 }; | |
| 136 | |
| 137 // The socket that created this object. | |
| 138 TCPClientSocketWin* socket_; | |
| 139 | |
| 140 // |reader_| handles the signals from |read_watcher_|. | |
| 141 ReadDelegate reader_; | |
| 142 // |writer_| handles the signals from |write_watcher_|. | |
| 143 WriteDelegate writer_; | |
| 144 | |
| 145 // |read_watcher_| watches for events from Connect() and Read(). | |
| 146 base::ObjectWatcher read_watcher_; | |
| 147 // |write_watcher_| watches for events from Write(); | |
| 148 base::ObjectWatcher write_watcher_; | |
| 149 | |
| 150 DISALLOW_COPY_AND_ASSIGN(Core); | |
| 151 }; | |
| 152 | |
| 153 TCPClientSocketWin::Core::Core( | |
| 154 TCPClientSocketWin* socket) | |
| 155 : socket_(socket), | |
| 156 ALLOW_THIS_IN_INITIALIZER_LIST(reader_(this)), | |
| 157 ALLOW_THIS_IN_INITIALIZER_LIST(writer_(this)) { | |
| 158 memset(&read_overlapped_, 0, sizeof(read_overlapped_)); | |
| 159 memset(&write_overlapped_, 0, sizeof(write_overlapped_)); | |
| 160 } | |
| 161 | |
| 162 TCPClientSocketWin::Core::~Core() { | |
| 163 // Make sure the message loop is not watching this object anymore. | |
| 164 read_watcher_.StopWatching(); | |
| 165 write_watcher_.StopWatching(); | |
| 166 | |
| 167 WSACloseEvent(read_overlapped_.hEvent); | |
| 168 memset(&read_overlapped_, 0, sizeof(read_overlapped_)); | |
| 169 WSACloseEvent(write_overlapped_.hEvent); | |
| 170 memset(&write_overlapped_, 0, sizeof(write_overlapped_)); | |
| 171 } | |
| 172 | |
| 173 void TCPClientSocketWin::Core::WatchForRead() { | |
| 174 // We grab an extra reference because there is an IO operation in progress. | |
| 175 // Balanced in ReadDelegate::OnObjectSignaled(). | |
| 176 AddRef(); | |
| 177 read_watcher_.StartWatching(read_overlapped_.hEvent, &reader_); | |
| 178 } | |
| 179 | |
| 180 void TCPClientSocketWin::Core::WatchForWrite() { | |
| 181 // We grab an extra reference because there is an IO operation in progress. | |
| 182 // Balanced in WriteDelegate::OnObjectSignaled(). | |
| 183 AddRef(); | |
| 184 write_watcher_.StartWatching(write_overlapped_.hEvent, &writer_); | |
| 185 } | |
| 186 | |
| 187 void TCPClientSocketWin::Core::ReadDelegate::OnObjectSignaled( | |
| 188 HANDLE object) { | |
| 189 DCHECK_EQ(object, core_->read_overlapped_.hEvent); | |
| 190 if (core_->socket_) { | |
| 191 if (core_->socket_->waiting_connect_) { | |
| 192 core_->socket_->DidCompleteConnect(); | |
| 193 } else { | |
| 194 core_->socket_->DidCompleteRead(); | |
| 195 } | |
| 196 } | |
| 197 | |
| 198 core_->Release(); | |
| 199 } | |
| 200 | |
| 201 void TCPClientSocketWin::Core::WriteDelegate::OnObjectSignaled( | |
| 202 HANDLE object) { | |
| 203 DCHECK_EQ(object, core_->write_overlapped_.hEvent); | |
| 204 if (core_->socket_) | |
| 205 core_->socket_->DidCompleteWrite(); | |
| 206 | |
| 207 core_->Release(); | |
| 208 } | |
| 209 | |
| 210 //----------------------------------------------------------------------------- | |
| 211 | |
| 212 TCPClientSocketWin::TCPClientSocketWin(const AddressList& addresses) | |
| 213 : socket_(INVALID_SOCKET), | |
| 214 addresses_(addresses), | |
| 215 current_ai_(addresses_.head()), | |
| 216 waiting_connect_(false), | |
| 217 waiting_read_(false), | |
| 218 waiting_write_(false), | |
| 219 read_callback_(NULL), | |
| 220 write_callback_(NULL) { | |
| 221 EnsureWinsockInit(); | |
| 222 } | |
| 223 | |
| 224 TCPClientSocketWin::~TCPClientSocketWin() { | |
| 225 Disconnect(); | |
| 226 } | |
| 227 | |
| 228 int TCPClientSocketWin::Connect(CompletionCallback* callback) { | |
| 229 // If already connected, then just return OK. | |
| 230 if (socket_ != INVALID_SOCKET) | |
| 231 return OK; | |
| 232 | |
| 233 TRACE_EVENT_BEGIN("socket.connect", this, ""); | |
| 234 const struct addrinfo* ai = current_ai_; | |
| 235 DCHECK(ai); | |
| 236 | |
| 237 int rv = CreateSocket(ai); | |
| 238 if (rv != OK) | |
| 239 return rv; | |
| 240 | |
| 241 DCHECK(!core_); | |
| 242 core_ = new Core(this); | |
| 243 | |
| 244 // WSACreateEvent creates a manual-reset event object. | |
| 245 core_->read_overlapped_.hEvent = WSACreateEvent(); | |
| 246 // WSAEventSelect sets the socket to non-blocking mode as a side effect. | |
| 247 // Our connect() and recv() calls require that the socket be non-blocking. | |
| 248 WSAEventSelect(socket_, core_->read_overlapped_.hEvent, FD_CONNECT); | |
| 249 | |
| 250 core_->write_overlapped_.hEvent = WSACreateEvent(); | |
| 251 | |
| 252 if (!connect(socket_, ai->ai_addr, static_cast<int>(ai->ai_addrlen))) { | |
| 253 // Connected without waiting! | |
| 254 // | |
| 255 // The MSDN page for connect says: | |
| 256 // With a nonblocking socket, the connection attempt cannot be completed | |
| 257 // immediately. In this case, connect will return SOCKET_ERROR, and | |
| 258 // WSAGetLastError will return WSAEWOULDBLOCK. | |
| 259 // which implies that for a nonblocking socket, connect never returns 0. | |
| 260 // It's not documented whether the event object will be signaled or not | |
| 261 // if connect does return 0. So the code below is essentially dead code | |
| 262 // and we don't know if it's correct. | |
| 263 NOTREACHED(); | |
| 264 | |
| 265 if (ResetEventIfSignaled(core_->read_overlapped_.hEvent)) { | |
| 266 TRACE_EVENT_END("socket.connect", this, ""); | |
| 267 return OK; | |
| 268 } | |
| 269 } else { | |
| 270 DWORD err = WSAGetLastError(); | |
| 271 if (err != WSAEWOULDBLOCK) { | |
| 272 LOG(ERROR) << "connect failed: " << err; | |
| 273 return MapWinsockError(err); | |
| 274 } | |
| 275 } | |
| 276 | |
| 277 core_->WatchForRead(); | |
| 278 waiting_connect_ = true; | |
| 279 read_callback_ = callback; | |
| 280 return ERR_IO_PENDING; | |
| 281 } | |
| 282 | |
| 283 void TCPClientSocketWin::Disconnect() { | |
| 284 if (socket_ == INVALID_SOCKET) | |
| 285 return; | |
| 286 | |
| 287 TRACE_EVENT_INSTANT("socket.disconnect", this, ""); | |
| 288 | |
| 289 // Note: don't use CancelIo to cancel pending IO because it doesn't work | |
| 290 // when there is a Winsock layered service provider. | |
| 291 | |
| 292 // In most socket implementations, closing a socket results in a graceful | |
| 293 // connection shutdown, but in Winsock we have to call shutdown explicitly. | |
| 294 // See the MSDN page "Graceful Shutdown, Linger Options, and Socket Closure" | |
| 295 // at http://msdn.microsoft.com/en-us/library/ms738547.aspx | |
| 296 shutdown(socket_, SD_SEND); | |
| 297 | |
| 298 // This cancels any pending IO. | |
| 299 closesocket(socket_); | |
| 300 socket_ = INVALID_SOCKET; | |
| 301 | |
| 302 // Reset for next time. | |
| 303 current_ai_ = addresses_.head(); | |
| 304 | |
| 305 if (waiting_connect_) { | |
| 306 // We closed the socket, so this notification will never come. | |
| 307 // From MSDN' WSAEventSelect documentation: | |
| 308 // "Closing a socket with closesocket also cancels the association and | |
| 309 // selection of network events specified in WSAEventSelect for the socket". | |
| 310 core_->Release(); | |
| 311 } | |
| 312 | |
| 313 waiting_read_ = false; | |
| 314 waiting_write_ = false; | |
| 315 waiting_connect_ = false; | |
| 316 | |
| 317 core_->Detach(); | |
| 318 core_ = NULL; | |
| 319 } | |
| 320 | |
| 321 bool TCPClientSocketWin::IsConnected() const { | |
| 322 if (socket_ == INVALID_SOCKET || waiting_connect_) | |
| 323 return false; | |
| 324 | |
| 325 // Check if connection is alive. | |
| 326 char c; | |
| 327 int rv = recv(socket_, &c, 1, MSG_PEEK); | |
| 328 if (rv == 0) | |
| 329 return false; | |
| 330 if (rv == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) | |
| 331 return false; | |
| 332 | |
| 333 return true; | |
| 334 } | |
| 335 | |
| 336 bool TCPClientSocketWin::IsConnectedAndIdle() const { | |
| 337 if (socket_ == INVALID_SOCKET || waiting_connect_) | |
| 338 return false; | |
| 339 | |
| 340 // Check if connection is alive and we haven't received any data | |
| 341 // unexpectedly. | |
| 342 char c; | |
| 343 int rv = recv(socket_, &c, 1, MSG_PEEK); | |
| 344 if (rv >= 0) | |
| 345 return false; | |
| 346 if (WSAGetLastError() != WSAEWOULDBLOCK) | |
| 347 return false; | |
| 348 | |
| 349 return true; | |
| 350 } | |
| 351 | |
| 352 int TCPClientSocketWin::Read(IOBuffer* buf, | |
| 353 int buf_len, | |
| 354 CompletionCallback* callback) { | |
| 355 DCHECK_NE(socket_, INVALID_SOCKET); | |
| 356 DCHECK(!waiting_read_); | |
| 357 DCHECK(!read_callback_); | |
| 358 DCHECK(!core_->read_iobuffer_); | |
| 359 | |
| 360 core_->read_buffer_.len = buf_len; | |
| 361 core_->read_buffer_.buf = buf->data(); | |
| 362 | |
| 363 TRACE_EVENT_BEGIN("socket.read", this, ""); | |
| 364 // TODO(wtc): Remove the CHECK after enough testing. | |
| 365 CHECK(WaitForSingleObject(core_->read_overlapped_.hEvent, 0) == WAIT_TIMEOUT); | |
| 366 DWORD num, flags = 0; | |
| 367 int rv = WSARecv(socket_, &core_->read_buffer_, 1, &num, &flags, | |
| 368 &core_->read_overlapped_, NULL); | |
| 369 if (rv == 0) { | |
| 370 if (ResetEventIfSignaled(core_->read_overlapped_.hEvent)) { | |
| 371 TRACE_EVENT_END("socket.read", this, StringPrintf("%d bytes", num)); | |
| 372 | |
| 373 // Because of how WSARecv fills memory when used asynchronously, Purify | |
| 374 // isn't able to detect that it's been initialized, so it scans for 0xcd | |
| 375 // in the buffer and reports UMRs (uninitialized memory reads) for those | |
| 376 // individual bytes. We override that in PURIFY builds to avoid the | |
| 377 // false error reports. | |
| 378 // See bug 5297. | |
| 379 base::MemoryDebug::MarkAsInitialized(core_->read_buffer_.buf, num); | |
| 380 return static_cast<int>(num); | |
| 381 } | |
| 382 } else { | |
| 383 int err = WSAGetLastError(); | |
| 384 if (err != WSA_IO_PENDING) | |
| 385 return MapWinsockError(err); | |
| 386 } | |
| 387 core_->WatchForRead(); | |
| 388 waiting_read_ = true; | |
| 389 read_callback_ = callback; | |
| 390 core_->read_iobuffer_ = buf; | |
| 391 return ERR_IO_PENDING; | |
| 392 } | |
| 393 | |
| 394 int TCPClientSocketWin::Write(IOBuffer* buf, | |
| 395 int buf_len, | |
| 396 CompletionCallback* callback) { | |
| 397 DCHECK_NE(socket_, INVALID_SOCKET); | |
| 398 DCHECK(!waiting_write_); | |
| 399 DCHECK(!write_callback_); | |
| 400 DCHECK_GT(buf_len, 0); | |
| 401 DCHECK(!core_->write_iobuffer_); | |
| 402 | |
| 403 core_->write_buffer_.len = buf_len; | |
| 404 core_->write_buffer_.buf = buf->data(); | |
| 405 | |
| 406 TRACE_EVENT_BEGIN("socket.write", this, ""); | |
| 407 // TODO(wtc): Remove the CHECK after enough testing. | |
| 408 CHECK( | |
| 409 WaitForSingleObject(core_->write_overlapped_.hEvent, 0) == WAIT_TIMEOUT); | |
| 410 DWORD num; | |
| 411 int rv = WSASend(socket_, &core_->write_buffer_, 1, &num, 0, | |
| 412 &core_->write_overlapped_, NULL); | |
| 413 if (rv == 0) { | |
| 414 if (ResetEventIfSignaled(core_->write_overlapped_.hEvent)) { | |
| 415 TRACE_EVENT_END("socket.write", this, StringPrintf("%d bytes", num)); | |
| 416 return static_cast<int>(num); | |
| 417 } | |
| 418 } else { | |
| 419 int err = WSAGetLastError(); | |
| 420 if (err != WSA_IO_PENDING) | |
| 421 return MapWinsockError(err); | |
| 422 } | |
| 423 core_->WatchForWrite(); | |
| 424 waiting_write_ = true; | |
| 425 write_callback_ = callback; | |
| 426 core_->write_iobuffer_ = buf; | |
| 427 return ERR_IO_PENDING; | |
| 428 } | |
| 429 | |
| 430 int TCPClientSocketWin::CreateSocket(const struct addrinfo* ai) { | |
| 431 socket_ = WSASocket(ai->ai_family, ai->ai_socktype, ai->ai_protocol, NULL, 0, | |
| 432 WSA_FLAG_OVERLAPPED); | |
| 433 if (socket_ == INVALID_SOCKET) { | |
| 434 DWORD err = WSAGetLastError(); | |
| 435 LOG(ERROR) << "WSASocket failed: " << err; | |
| 436 return MapWinsockError(err); | |
| 437 } | |
| 438 | |
| 439 // Increase the socket buffer sizes from the default sizes for WinXP. In | |
| 440 // performance testing, there is substantial benefit by increasing from 8KB | |
| 441 // to 64KB. | |
| 442 // See also: | |
| 443 // http://support.microsoft.com/kb/823764/EN-US | |
| 444 // On Vista, if we manually set these sizes, Vista turns off its receive | |
| 445 // window auto-tuning feature. | |
| 446 // http://blogs.msdn.com/wndp/archive/2006/05/05/Winhec-blog-tcpip-2.aspx | |
| 447 // Since Vista's auto-tune is better than any static value we can could set, | |
| 448 // only change these on pre-vista machines. | |
| 449 int32 major_version, minor_version, fix_version; | |
| 450 base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version, | |
| 451 &fix_version); | |
| 452 if (major_version < 6) { | |
| 453 const int kSocketBufferSize = 64 * 1024; | |
| 454 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, | |
| 455 reinterpret_cast<const char*>(&kSocketBufferSize), | |
| 456 sizeof(kSocketBufferSize)); | |
| 457 DCHECK(!rv) << "Could not set socket send buffer size"; | |
| 458 rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, | |
| 459 reinterpret_cast<const char*>(&kSocketBufferSize), | |
| 460 sizeof(kSocketBufferSize)); | |
| 461 DCHECK(!rv) << "Could not set socket receive buffer size"; | |
| 462 } | |
| 463 | |
| 464 // Disable Nagle. | |
| 465 // The Nagle implementation on windows is governed by RFC 896. The idea | |
| 466 // behind Nagle is to reduce small packets on the network. When Nagle is | |
| 467 // enabled, if a partial packet has been sent, the TCP stack will disallow | |
| 468 // further *partial* packets until an ACK has been received from the other | |
| 469 // side. Good applications should always strive to send as much data as | |
| 470 // possible and avoid partial-packet sends. However, in most real world | |
| 471 // applications, there are edge cases where this does not happen, and two | |
| 472 // partil packets may be sent back to back. For a browser, it is NEVER | |
| 473 // a benefit to delay for an RTT before the second packet is sent. | |
| 474 // | |
| 475 // As a practical example in Chromium today, consider the case of a small | |
| 476 // POST. I have verified this: | |
| 477 // Client writes 649 bytes of header (partial packet #1) | |
| 478 // Client writes 50 bytes of POST data (partial packet #2) | |
| 479 // In the above example, with Nagle, a RTT delay is inserted between these | |
| 480 // two sends due to nagle. RTTs can easily be 100ms or more. The best | |
| 481 // fix is to make sure that for POSTing data, we write as much data as | |
| 482 // possible and minimize partial packets. We will fix that. But disabling | |
| 483 // Nagle also ensure we don't run into this delay in other edge cases. | |
| 484 // See also: | |
| 485 // http://technet.microsoft.com/en-us/library/bb726981.aspx | |
| 486 const BOOL kDisableNagle = TRUE; | |
| 487 int rv = setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, | |
| 488 reinterpret_cast<const char*>(&kDisableNagle), sizeof(kDisableNagle)); | |
| 489 DCHECK(!rv) << "Could not disable nagle"; | |
| 490 | |
| 491 return OK; | |
| 492 } | |
| 493 | |
| 494 void TCPClientSocketWin::DoReadCallback(int rv) { | |
| 495 DCHECK_NE(rv, ERR_IO_PENDING); | |
| 496 DCHECK(read_callback_); | |
| 497 | |
| 498 // since Run may result in Read being called, clear read_callback_ up front. | |
| 499 CompletionCallback* c = read_callback_; | |
| 500 read_callback_ = NULL; | |
| 501 c->Run(rv); | |
| 502 } | |
| 503 | |
| 504 void TCPClientSocketWin::DoWriteCallback(int rv) { | |
| 505 DCHECK_NE(rv, ERR_IO_PENDING); | |
| 506 DCHECK(write_callback_); | |
| 507 | |
| 508 // since Run may result in Write being called, clear write_callback_ up front. | |
| 509 CompletionCallback* c = write_callback_; | |
| 510 write_callback_ = NULL; | |
| 511 c->Run(rv); | |
| 512 } | |
| 513 | |
| 514 void TCPClientSocketWin::DidCompleteConnect() { | |
| 515 DCHECK(waiting_connect_); | |
| 516 int result; | |
| 517 | |
| 518 TRACE_EVENT_END("socket.connect", this, ""); | |
| 519 waiting_connect_ = false; | |
| 520 | |
| 521 WSANETWORKEVENTS events; | |
| 522 int rv = WSAEnumNetworkEvents(socket_, core_->read_overlapped_.hEvent, | |
| 523 &events); | |
| 524 if (rv == SOCKET_ERROR) { | |
| 525 NOTREACHED(); | |
| 526 result = MapWinsockError(WSAGetLastError()); | |
| 527 } else if (events.lNetworkEvents & FD_CONNECT) { | |
| 528 DWORD error_code = static_cast<DWORD>(events.iErrorCode[FD_CONNECT_BIT]); | |
| 529 if (current_ai_->ai_next && ( | |
| 530 error_code == WSAEADDRNOTAVAIL || | |
| 531 error_code == WSAEAFNOSUPPORT || | |
| 532 error_code == WSAECONNREFUSED || | |
| 533 error_code == WSAENETUNREACH || | |
| 534 error_code == WSAEHOSTUNREACH || | |
| 535 error_code == WSAETIMEDOUT)) { | |
| 536 // Try using the next address. | |
| 537 const struct addrinfo* next = current_ai_->ai_next; | |
| 538 Disconnect(); | |
| 539 current_ai_ = next; | |
| 540 result = Connect(read_callback_); | |
| 541 } else { | |
| 542 result = MapWinsockError(error_code); | |
| 543 } | |
| 544 } else { | |
| 545 NOTREACHED(); | |
| 546 result = ERR_UNEXPECTED; | |
| 547 } | |
| 548 | |
| 549 if (result != ERR_IO_PENDING) | |
| 550 DoReadCallback(result); | |
| 551 } | |
| 552 | |
| 553 void TCPClientSocketWin::DidCompleteRead() { | |
| 554 DCHECK(waiting_read_); | |
| 555 DWORD num_bytes, flags; | |
| 556 BOOL ok = WSAGetOverlappedResult(socket_, &core_->read_overlapped_, | |
| 557 &num_bytes, FALSE, &flags); | |
| 558 WSAResetEvent(core_->read_overlapped_.hEvent); | |
| 559 TRACE_EVENT_END("socket.read", this, StringPrintf("%d bytes", num_bytes)); | |
| 560 waiting_read_ = false; | |
| 561 core_->read_iobuffer_ = NULL; | |
| 562 DoReadCallback(ok ? num_bytes : MapWinsockError(WSAGetLastError())); | |
| 563 } | |
| 564 | |
| 565 void TCPClientSocketWin::DidCompleteWrite() { | |
| 566 DCHECK(waiting_write_); | |
| 567 | |
| 568 DWORD num_bytes, flags; | |
| 569 BOOL ok = WSAGetOverlappedResult(socket_, &core_->write_overlapped_, | |
| 570 &num_bytes, FALSE, &flags); | |
| 571 WSAResetEvent(core_->write_overlapped_.hEvent); | |
| 572 TRACE_EVENT_END("socket.write", this, StringPrintf("%d bytes", num_bytes)); | |
| 573 waiting_write_ = false; | |
| 574 core_->write_iobuffer_ = NULL; | |
| 575 DoWriteCallback(ok ? num_bytes : MapWinsockError(WSAGetLastError())); | |
| 576 } | |
| 577 | |
| 578 } // namespace net | |
| OLD | NEW |