OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/socket/tcp_socket.h" | |
6 #include "net/socket/tcp_socket_win.h" | |
7 | |
8 #include <mstcpip.h> | |
9 | |
10 #include "base/callback_helpers.h" | |
11 #include "base/logging.h" | |
12 #include "base/profiler/scoped_tracker.h" | |
13 #include "base/win/windows_version.h" | |
14 #include "net/base/address_list.h" | |
15 #include "net/base/connection_type_histograms.h" | |
16 #include "net/base/io_buffer.h" | |
17 #include "net/base/ip_endpoint.h" | |
18 #include "net/base/net_errors.h" | |
19 #include "net/base/net_util.h" | |
20 #include "net/base/network_activity_monitor.h" | |
21 #include "net/base/network_change_notifier.h" | |
22 #include "net/base/winsock_init.h" | |
23 #include "net/base/winsock_util.h" | |
24 #include "net/socket/socket_descriptor.h" | |
25 #include "net/socket/socket_net_log_params.h" | |
26 | |
27 namespace net { | |
28 | |
29 namespace { | |
30 | |
31 const int kTCPKeepAliveSeconds = 45; | |
32 | |
33 int SetSocketReceiveBufferSize(SOCKET socket, int32 size) { | |
34 int rv = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, | |
35 reinterpret_cast<const char*>(&size), sizeof(size)); | |
36 int net_error = (rv == 0) ? OK : MapSystemError(WSAGetLastError()); | |
37 DCHECK(!rv) << "Could not set socket receive buffer size: " << net_error; | |
38 return net_error; | |
39 } | |
40 | |
41 int SetSocketSendBufferSize(SOCKET socket, int32 size) { | |
42 int rv = setsockopt(socket, SOL_SOCKET, SO_SNDBUF, | |
43 reinterpret_cast<const char*>(&size), sizeof(size)); | |
44 int net_error = (rv == 0) ? OK : MapSystemError(WSAGetLastError()); | |
45 DCHECK(!rv) << "Could not set socket send buffer size: " << net_error; | |
46 return net_error; | |
47 } | |
48 | |
49 // Disable Nagle. | |
50 // The Nagle implementation on windows is governed by RFC 896. The idea | |
51 // behind Nagle is to reduce small packets on the network. When Nagle is | |
52 // enabled, if a partial packet has been sent, the TCP stack will disallow | |
53 // further *partial* packets until an ACK has been received from the other | |
54 // side. Good applications should always strive to send as much data as | |
55 // possible and avoid partial-packet sends. However, in most real world | |
56 // applications, there are edge cases where this does not happen, and two | |
57 // partial packets may be sent back to back. For a browser, it is NEVER | |
58 // a benefit to delay for an RTT before the second packet is sent. | |
59 // | |
60 // As a practical example in Chromium today, consider the case of a small | |
61 // POST. I have verified this: | |
62 // Client writes 649 bytes of header (partial packet #1) | |
63 // Client writes 50 bytes of POST data (partial packet #2) | |
64 // In the above example, with Nagle, a RTT delay is inserted between these | |
65 // two sends due to nagle. RTTs can easily be 100ms or more. The best | |
66 // fix is to make sure that for POSTing data, we write as much data as | |
67 // possible and minimize partial packets. We will fix that. But disabling | |
68 // Nagle also ensure we don't run into this delay in other edge cases. | |
69 // See also: | |
70 // http://technet.microsoft.com/en-us/library/bb726981.aspx | |
71 bool DisableNagle(SOCKET socket, bool disable) { | |
72 BOOL val = disable ? TRUE : FALSE; | |
73 int rv = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, | |
74 reinterpret_cast<const char*>(&val), | |
75 sizeof(val)); | |
76 DCHECK(!rv) << "Could not disable nagle"; | |
77 return rv == 0; | |
78 } | |
79 | |
80 // Enable TCP Keep-Alive to prevent NAT routers from timing out TCP | |
81 // connections. See http://crbug.com/27400 for details. | |
82 bool SetTCPKeepAlive(SOCKET socket, BOOL enable, int delay_secs) { | |
83 int delay = delay_secs * 1000; | |
84 struct tcp_keepalive keepalive_vals = { | |
85 enable ? 1 : 0, // TCP keep-alive on. | |
86 delay, // Delay seconds before sending first TCP keep-alive packet. | |
87 delay, // Delay seconds between sending TCP keep-alive packets. | |
88 }; | |
89 DWORD bytes_returned = 0xABAB; | |
90 int rv = WSAIoctl(socket, SIO_KEEPALIVE_VALS, &keepalive_vals, | |
91 sizeof(keepalive_vals), NULL, 0, | |
92 &bytes_returned, NULL, NULL); | |
93 DCHECK(!rv) << "Could not enable TCP Keep-Alive for socket: " << socket | |
94 << " [error: " << WSAGetLastError() << "]."; | |
95 | |
96 // Disregard any failure in disabling nagle or enabling TCP Keep-Alive. | |
97 return rv == 0; | |
98 } | |
99 | |
100 int MapConnectError(int os_error) { | |
101 switch (os_error) { | |
102 // connect fails with WSAEACCES when Windows Firewall blocks the | |
103 // connection. | |
104 case WSAEACCES: | |
105 return ERR_NETWORK_ACCESS_DENIED; | |
106 case WSAETIMEDOUT: | |
107 return ERR_CONNECTION_TIMED_OUT; | |
108 default: { | |
109 int net_error = MapSystemError(os_error); | |
110 if (net_error == ERR_FAILED) | |
111 return ERR_CONNECTION_FAILED; // More specific than ERR_FAILED. | |
112 | |
113 // Give a more specific error when the user is offline. | |
114 if (net_error == ERR_ADDRESS_UNREACHABLE && | |
115 NetworkChangeNotifier::IsOffline()) { | |
116 return ERR_INTERNET_DISCONNECTED; | |
117 } | |
118 | |
119 return net_error; | |
120 } | |
121 } | |
122 } | |
123 | |
124 } // namespace | |
125 | |
126 //----------------------------------------------------------------------------- | |
127 | |
128 // Nothing to do for Windows since it doesn't support TCP FastOpen. | |
129 // TODO(jri): Remove these along with the corresponding global variables. | |
130 bool IsTCPFastOpenSupported() { return false; } | |
131 bool IsTCPFastOpenUserEnabled() { return false; } | |
132 void CheckSupportAndMaybeEnableTCPFastOpen(bool user_enabled) {} | |
133 | |
134 // This class encapsulates all the state that has to be preserved as long as | |
135 // there is a network IO operation in progress. If the owner TCPSocketWin is | |
136 // destroyed while an operation is in progress, the Core is detached and it | |
137 // lives until the operation completes and the OS doesn't reference any resource | |
138 // declared on this class anymore. | |
139 class TCPSocketWin::Core : public base::RefCounted<Core> { | |
140 public: | |
141 explicit Core(TCPSocketWin* socket); | |
142 | |
143 // Start watching for the end of a read or write operation. | |
144 void WatchForRead(); | |
145 void WatchForWrite(); | |
146 | |
147 // The TCPSocketWin is going away. | |
148 void Detach() { socket_ = NULL; } | |
149 | |
150 // The separate OVERLAPPED variables for asynchronous operation. | |
151 // |read_overlapped_| is used for both Connect() and Read(). | |
152 // |write_overlapped_| is only used for Write(); | |
153 OVERLAPPED read_overlapped_; | |
154 OVERLAPPED write_overlapped_; | |
155 | |
156 // The buffers used in Read() and Write(). | |
157 scoped_refptr<IOBuffer> read_iobuffer_; | |
158 scoped_refptr<IOBuffer> write_iobuffer_; | |
159 int read_buffer_length_; | |
160 int write_buffer_length_; | |
161 | |
162 bool non_blocking_reads_initialized_; | |
163 | |
164 private: | |
165 friend class base::RefCounted<Core>; | |
166 | |
167 class ReadDelegate : public base::win::ObjectWatcher::Delegate { | |
168 public: | |
169 explicit ReadDelegate(Core* core) : core_(core) {} | |
170 virtual ~ReadDelegate() {} | |
171 | |
172 // base::ObjectWatcher::Delegate methods: | |
173 virtual void OnObjectSignaled(HANDLE object); | |
174 | |
175 private: | |
176 Core* const core_; | |
177 }; | |
178 | |
179 class WriteDelegate : public base::win::ObjectWatcher::Delegate { | |
180 public: | |
181 explicit WriteDelegate(Core* core) : core_(core) {} | |
182 virtual ~WriteDelegate() {} | |
183 | |
184 // base::ObjectWatcher::Delegate methods: | |
185 virtual void OnObjectSignaled(HANDLE object); | |
186 | |
187 private: | |
188 Core* const core_; | |
189 }; | |
190 | |
191 ~Core(); | |
192 | |
193 // The socket that created this object. | |
194 TCPSocketWin* socket_; | |
195 | |
196 // |reader_| handles the signals from |read_watcher_|. | |
197 ReadDelegate reader_; | |
198 // |writer_| handles the signals from |write_watcher_|. | |
199 WriteDelegate writer_; | |
200 | |
201 // |read_watcher_| watches for events from Connect() and Read(). | |
202 base::win::ObjectWatcher read_watcher_; | |
203 // |write_watcher_| watches for events from Write(); | |
204 base::win::ObjectWatcher write_watcher_; | |
205 | |
206 DISALLOW_COPY_AND_ASSIGN(Core); | |
207 }; | |
208 | |
209 TCPSocketWin::Core::Core(TCPSocketWin* socket) | |
210 : read_buffer_length_(0), | |
211 write_buffer_length_(0), | |
212 non_blocking_reads_initialized_(false), | |
213 socket_(socket), | |
214 reader_(this), | |
215 writer_(this) { | |
216 memset(&read_overlapped_, 0, sizeof(read_overlapped_)); | |
217 memset(&write_overlapped_, 0, sizeof(write_overlapped_)); | |
218 | |
219 read_overlapped_.hEvent = WSACreateEvent(); | |
220 write_overlapped_.hEvent = WSACreateEvent(); | |
221 } | |
222 | |
223 TCPSocketWin::Core::~Core() { | |
224 // Make sure the message loop is not watching this object anymore. | |
225 read_watcher_.StopWatching(); | |
226 write_watcher_.StopWatching(); | |
227 | |
228 WSACloseEvent(read_overlapped_.hEvent); | |
229 memset(&read_overlapped_, 0xaf, sizeof(read_overlapped_)); | |
230 WSACloseEvent(write_overlapped_.hEvent); | |
231 memset(&write_overlapped_, 0xaf, sizeof(write_overlapped_)); | |
232 } | |
233 | |
234 void TCPSocketWin::Core::WatchForRead() { | |
235 // We grab an extra reference because there is an IO operation in progress. | |
236 // Balanced in ReadDelegate::OnObjectSignaled(). | |
237 AddRef(); | |
238 read_watcher_.StartWatching(read_overlapped_.hEvent, &reader_); | |
239 } | |
240 | |
241 void TCPSocketWin::Core::WatchForWrite() { | |
242 // We grab an extra reference because there is an IO operation in progress. | |
243 // Balanced in WriteDelegate::OnObjectSignaled(). | |
244 AddRef(); | |
245 write_watcher_.StartWatching(write_overlapped_.hEvent, &writer_); | |
246 } | |
247 | |
248 void TCPSocketWin::Core::ReadDelegate::OnObjectSignaled(HANDLE object) { | |
249 // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is fixed. | |
250 tracked_objects::ScopedTracker tracking_profile( | |
251 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
252 "418183 TCPSocketWin::Core::ReadDelegate::OnObjectSignaled")); | |
253 | |
254 DCHECK_EQ(object, core_->read_overlapped_.hEvent); | |
255 if (core_->socket_) { | |
256 if (core_->socket_->waiting_connect_) | |
257 core_->socket_->DidCompleteConnect(); | |
258 else | |
259 core_->socket_->DidSignalRead(); | |
260 } | |
261 | |
262 core_->Release(); | |
263 } | |
264 | |
265 void TCPSocketWin::Core::WriteDelegate::OnObjectSignaled( | |
266 HANDLE object) { | |
267 // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is fixed. | |
268 tracked_objects::ScopedTracker tracking_profile( | |
269 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
270 "418183 TCPSocketWin::Core::WriteDelegate::OnObjectSignaled")); | |
271 | |
272 DCHECK_EQ(object, core_->write_overlapped_.hEvent); | |
273 if (core_->socket_) | |
274 core_->socket_->DidCompleteWrite(); | |
275 | |
276 core_->Release(); | |
277 } | |
278 | |
279 //----------------------------------------------------------------------------- | |
280 | |
281 TCPSocketWin::TCPSocketWin(net::NetLog* net_log, | |
282 const net::NetLog::Source& source) | |
283 : socket_(INVALID_SOCKET), | |
284 accept_event_(WSA_INVALID_EVENT), | |
285 accept_socket_(NULL), | |
286 accept_address_(NULL), | |
287 waiting_connect_(false), | |
288 waiting_read_(false), | |
289 waiting_write_(false), | |
290 connect_os_error_(0), | |
291 logging_multiple_connect_attempts_(false), | |
292 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) { | |
293 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, | |
294 source.ToEventParametersCallback()); | |
295 EnsureWinsockInit(); | |
296 } | |
297 | |
298 TCPSocketWin::~TCPSocketWin() { | |
299 Close(); | |
300 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE); | |
301 } | |
302 | |
303 int TCPSocketWin::Open(AddressFamily family) { | |
304 DCHECK(CalledOnValidThread()); | |
305 DCHECK_EQ(socket_, INVALID_SOCKET); | |
306 | |
307 socket_ = CreatePlatformSocket(ConvertAddressFamily(family), SOCK_STREAM, | |
308 IPPROTO_TCP); | |
309 if (socket_ == INVALID_SOCKET) { | |
310 PLOG(ERROR) << "CreatePlatformSocket() returned an error"; | |
311 return MapSystemError(WSAGetLastError()); | |
312 } | |
313 | |
314 if (SetNonBlocking(socket_)) { | |
315 int result = MapSystemError(WSAGetLastError()); | |
316 Close(); | |
317 return result; | |
318 } | |
319 | |
320 return OK; | |
321 } | |
322 | |
323 int TCPSocketWin::AdoptConnectedSocket(SOCKET socket, | |
324 const IPEndPoint& peer_address) { | |
325 DCHECK(CalledOnValidThread()); | |
326 DCHECK_EQ(socket_, INVALID_SOCKET); | |
327 DCHECK(!core_.get()); | |
328 | |
329 socket_ = socket; | |
330 | |
331 if (SetNonBlocking(socket_)) { | |
332 int result = MapSystemError(WSAGetLastError()); | |
333 Close(); | |
334 return result; | |
335 } | |
336 | |
337 core_ = new Core(this); | |
338 peer_address_.reset(new IPEndPoint(peer_address)); | |
339 | |
340 return OK; | |
341 } | |
342 | |
343 int TCPSocketWin::AdoptListenSocket(SOCKET socket) { | |
344 DCHECK(CalledOnValidThread()); | |
345 DCHECK_EQ(socket_, INVALID_SOCKET); | |
346 | |
347 socket_ = socket; | |
348 | |
349 if (SetNonBlocking(socket_)) { | |
350 int result = MapSystemError(WSAGetLastError()); | |
351 Close(); | |
352 return result; | |
353 } | |
354 | |
355 // |core_| is not needed for sockets that are used to accept connections. | |
356 // The operation here is more like Open but with an existing socket. | |
357 | |
358 return OK; | |
359 } | |
360 | |
361 int TCPSocketWin::Bind(const IPEndPoint& address) { | |
362 DCHECK(CalledOnValidThread()); | |
363 DCHECK_NE(socket_, INVALID_SOCKET); | |
364 | |
365 SockaddrStorage storage; | |
366 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) | |
367 return ERR_ADDRESS_INVALID; | |
368 | |
369 int result = bind(socket_, storage.addr, storage.addr_len); | |
370 if (result < 0) { | |
371 PLOG(ERROR) << "bind() returned an error"; | |
372 return MapSystemError(WSAGetLastError()); | |
373 } | |
374 | |
375 return OK; | |
376 } | |
377 | |
378 int TCPSocketWin::Listen(int backlog) { | |
379 DCHECK(CalledOnValidThread()); | |
380 DCHECK_GT(backlog, 0); | |
381 DCHECK_NE(socket_, INVALID_SOCKET); | |
382 DCHECK_EQ(accept_event_, WSA_INVALID_EVENT); | |
383 | |
384 accept_event_ = WSACreateEvent(); | |
385 if (accept_event_ == WSA_INVALID_EVENT) { | |
386 PLOG(ERROR) << "WSACreateEvent()"; | |
387 return MapSystemError(WSAGetLastError()); | |
388 } | |
389 | |
390 int result = listen(socket_, backlog); | |
391 if (result < 0) { | |
392 PLOG(ERROR) << "listen() returned an error"; | |
393 return MapSystemError(WSAGetLastError()); | |
394 } | |
395 | |
396 return OK; | |
397 } | |
398 | |
399 int TCPSocketWin::Accept(scoped_ptr<TCPSocketWin>* socket, | |
400 IPEndPoint* address, | |
401 const CompletionCallback& callback) { | |
402 DCHECK(CalledOnValidThread()); | |
403 DCHECK(socket); | |
404 DCHECK(address); | |
405 DCHECK(!callback.is_null()); | |
406 DCHECK(accept_callback_.is_null()); | |
407 | |
408 net_log_.BeginEvent(NetLog::TYPE_TCP_ACCEPT); | |
409 | |
410 int result = AcceptInternal(socket, address); | |
411 | |
412 if (result == ERR_IO_PENDING) { | |
413 // Start watching. | |
414 WSAEventSelect(socket_, accept_event_, FD_ACCEPT); | |
415 accept_watcher_.StartWatching(accept_event_, this); | |
416 | |
417 accept_socket_ = socket; | |
418 accept_address_ = address; | |
419 accept_callback_ = callback; | |
420 } | |
421 | |
422 return result; | |
423 } | |
424 | |
425 int TCPSocketWin::Connect(const IPEndPoint& address, | |
426 const CompletionCallback& callback) { | |
427 // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. | |
428 tracked_objects::ScopedTracker tracking_profile( | |
429 FROM_HERE_WITH_EXPLICIT_FUNCTION("436634 TCPSocketWin::Connect")); | |
430 | |
431 DCHECK(CalledOnValidThread()); | |
432 DCHECK_NE(socket_, INVALID_SOCKET); | |
433 DCHECK(!waiting_connect_); | |
434 | |
435 // |peer_address_| and |core_| will be non-NULL if Connect() has been called. | |
436 // Unless Close() is called to reset the internal state, a second call to | |
437 // Connect() is not allowed. | |
438 // Please note that we enforce this even if the previous Connect() has | |
439 // completed and failed. Although it is allowed to connect the same |socket_| | |
440 // again after a connection attempt failed on Windows, it results in | |
441 // unspecified behavior according to POSIX. Therefore, we make it behave in | |
442 // the same way as TCPSocketLibevent. | |
443 DCHECK(!peer_address_ && !core_.get()); | |
444 | |
445 if (!logging_multiple_connect_attempts_) | |
446 LogConnectBegin(AddressList(address)); | |
447 | |
448 peer_address_.reset(new IPEndPoint(address)); | |
449 | |
450 int rv = DoConnect(); | |
451 if (rv == ERR_IO_PENDING) { | |
452 // Synchronous operation not supported. | |
453 DCHECK(!callback.is_null()); | |
454 read_callback_ = callback; | |
455 waiting_connect_ = true; | |
456 } else { | |
457 DoConnectComplete(rv); | |
458 } | |
459 | |
460 return rv; | |
461 } | |
462 | |
463 bool TCPSocketWin::IsConnected() const { | |
464 DCHECK(CalledOnValidThread()); | |
465 | |
466 if (socket_ == INVALID_SOCKET || waiting_connect_) | |
467 return false; | |
468 | |
469 if (waiting_read_) | |
470 return true; | |
471 | |
472 // Check if connection is alive. | |
473 char c; | |
474 int rv = recv(socket_, &c, 1, MSG_PEEK); | |
475 if (rv == 0) | |
476 return false; | |
477 if (rv == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) | |
478 return false; | |
479 | |
480 return true; | |
481 } | |
482 | |
483 bool TCPSocketWin::IsConnectedAndIdle() const { | |
484 DCHECK(CalledOnValidThread()); | |
485 | |
486 if (socket_ == INVALID_SOCKET || waiting_connect_) | |
487 return false; | |
488 | |
489 if (waiting_read_) | |
490 return true; | |
491 | |
492 // Check if connection is alive and we haven't received any data | |
493 // unexpectedly. | |
494 char c; | |
495 int rv = recv(socket_, &c, 1, MSG_PEEK); | |
496 if (rv >= 0) | |
497 return false; | |
498 if (WSAGetLastError() != WSAEWOULDBLOCK) | |
499 return false; | |
500 | |
501 return true; | |
502 } | |
503 | |
504 int TCPSocketWin::Read(IOBuffer* buf, | |
505 int buf_len, | |
506 const CompletionCallback& callback) { | |
507 DCHECK(CalledOnValidThread()); | |
508 DCHECK_NE(socket_, INVALID_SOCKET); | |
509 DCHECK(!waiting_read_); | |
510 CHECK(read_callback_.is_null()); | |
511 DCHECK(!core_->read_iobuffer_.get()); | |
512 | |
513 return DoRead(buf, buf_len, callback); | |
514 } | |
515 | |
516 int TCPSocketWin::Write(IOBuffer* buf, | |
517 int buf_len, | |
518 const CompletionCallback& callback) { | |
519 DCHECK(CalledOnValidThread()); | |
520 DCHECK_NE(socket_, INVALID_SOCKET); | |
521 DCHECK(!waiting_write_); | |
522 CHECK(write_callback_.is_null()); | |
523 DCHECK_GT(buf_len, 0); | |
524 DCHECK(!core_->write_iobuffer_.get()); | |
525 | |
526 WSABUF write_buffer; | |
527 write_buffer.len = buf_len; | |
528 write_buffer.buf = buf->data(); | |
529 | |
530 // TODO(wtc): Remove the assertion after enough testing. | |
531 AssertEventNotSignaled(core_->write_overlapped_.hEvent); | |
532 DWORD num; | |
533 int rv = WSASend(socket_, &write_buffer, 1, &num, 0, | |
534 &core_->write_overlapped_, NULL); | |
535 if (rv == 0) { | |
536 if (ResetEventIfSignaled(core_->write_overlapped_.hEvent)) { | |
537 rv = static_cast<int>(num); | |
538 if (rv > buf_len || rv < 0) { | |
539 // It seems that some winsock interceptors report that more was written | |
540 // than was available. Treat this as an error. http://crbug.com/27870 | |
541 LOG(ERROR) << "Detected broken LSP: Asked to write " << buf_len | |
542 << " bytes, but " << rv << " bytes reported."; | |
543 return ERR_WINSOCK_UNEXPECTED_WRITTEN_BYTES; | |
544 } | |
545 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, rv, | |
546 buf->data()); | |
547 NetworkActivityMonitor::GetInstance()->IncrementBytesSent(rv); | |
548 return rv; | |
549 } | |
550 } else { | |
551 int os_error = WSAGetLastError(); | |
552 if (os_error != WSA_IO_PENDING) { | |
553 int net_error = MapSystemError(os_error); | |
554 net_log_.AddEvent(NetLog::TYPE_SOCKET_WRITE_ERROR, | |
555 CreateNetLogSocketErrorCallback(net_error, os_error)); | |
556 return net_error; | |
557 } | |
558 } | |
559 waiting_write_ = true; | |
560 write_callback_ = callback; | |
561 core_->write_iobuffer_ = buf; | |
562 core_->write_buffer_length_ = buf_len; | |
563 core_->WatchForWrite(); | |
564 return ERR_IO_PENDING; | |
565 } | |
566 | |
567 int TCPSocketWin::GetLocalAddress(IPEndPoint* address) const { | |
568 DCHECK(CalledOnValidThread()); | |
569 DCHECK(address); | |
570 | |
571 SockaddrStorage storage; | |
572 if (getsockname(socket_, storage.addr, &storage.addr_len)) | |
573 return MapSystemError(WSAGetLastError()); | |
574 if (!address->FromSockAddr(storage.addr, storage.addr_len)) | |
575 return ERR_ADDRESS_INVALID; | |
576 | |
577 return OK; | |
578 } | |
579 | |
580 int TCPSocketWin::GetPeerAddress(IPEndPoint* address) const { | |
581 DCHECK(CalledOnValidThread()); | |
582 DCHECK(address); | |
583 if (!IsConnected()) | |
584 return ERR_SOCKET_NOT_CONNECTED; | |
585 *address = *peer_address_; | |
586 return OK; | |
587 } | |
588 | |
589 int TCPSocketWin::SetDefaultOptionsForServer() { | |
590 return SetExclusiveAddrUse(); | |
591 } | |
592 | |
593 void TCPSocketWin::SetDefaultOptionsForClient() { | |
594 // Increase the socket buffer sizes from the default sizes for WinXP. In | |
595 // performance testing, there is substantial benefit by increasing from 8KB | |
596 // to 64KB. | |
597 // See also: | |
598 // http://support.microsoft.com/kb/823764/EN-US | |
599 // On Vista, if we manually set these sizes, Vista turns off its receive | |
600 // window auto-tuning feature. | |
601 // http://blogs.msdn.com/wndp/archive/2006/05/05/Winhec-blog-tcpip-2.aspx | |
602 // Since Vista's auto-tune is better than any static value we can could set, | |
603 // only change these on pre-vista machines. | |
604 if (base::win::GetVersion() < base::win::VERSION_VISTA) { | |
605 const int32 kSocketBufferSize = 64 * 1024; | |
606 SetSocketReceiveBufferSize(socket_, kSocketBufferSize); | |
607 SetSocketSendBufferSize(socket_, kSocketBufferSize); | |
608 } | |
609 | |
610 DisableNagle(socket_, true); | |
611 SetTCPKeepAlive(socket_, true, kTCPKeepAliveSeconds); | |
612 } | |
613 | |
614 int TCPSocketWin::SetExclusiveAddrUse() { | |
615 // On Windows, a bound end point can be hijacked by another process by | |
616 // setting SO_REUSEADDR. Therefore a Windows-only option SO_EXCLUSIVEADDRUSE | |
617 // was introduced in Windows NT 4.0 SP4. If the socket that is bound to the | |
618 // end point has SO_EXCLUSIVEADDRUSE enabled, it is not possible for another | |
619 // socket to forcibly bind to the end point until the end point is unbound. | |
620 // It is recommend that all server applications must use SO_EXCLUSIVEADDRUSE. | |
621 // MSDN: http://goo.gl/M6fjQ. | |
622 // | |
623 // Unlike on *nix, on Windows a TCP server socket can always bind to an end | |
624 // point in TIME_WAIT state without setting SO_REUSEADDR, therefore it is not | |
625 // needed here. | |
626 // | |
627 // SO_EXCLUSIVEADDRUSE will prevent a TCP client socket from binding to an end | |
628 // point in TIME_WAIT status. It does not have this effect for a TCP server | |
629 // socket. | |
630 | |
631 BOOL true_value = 1; | |
632 int rv = setsockopt(socket_, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, | |
633 reinterpret_cast<const char*>(&true_value), | |
634 sizeof(true_value)); | |
635 if (rv < 0) | |
636 return MapSystemError(errno); | |
637 return OK; | |
638 } | |
639 | |
640 int TCPSocketWin::SetReceiveBufferSize(int32 size) { | |
641 DCHECK(CalledOnValidThread()); | |
642 return SetSocketReceiveBufferSize(socket_, size); | |
643 } | |
644 | |
645 int TCPSocketWin::SetSendBufferSize(int32 size) { | |
646 DCHECK(CalledOnValidThread()); | |
647 return SetSocketSendBufferSize(socket_, size); | |
648 } | |
649 | |
650 bool TCPSocketWin::SetKeepAlive(bool enable, int delay) { | |
651 return SetTCPKeepAlive(socket_, enable, delay); | |
652 } | |
653 | |
654 bool TCPSocketWin::SetNoDelay(bool no_delay) { | |
655 return DisableNagle(socket_, no_delay); | |
656 } | |
657 | |
658 void TCPSocketWin::Close() { | |
659 DCHECK(CalledOnValidThread()); | |
660 | |
661 if (socket_ != INVALID_SOCKET) { | |
662 // Only log the close event if there's actually a socket to close. | |
663 net_log_.AddEvent(NetLog::EventType::TYPE_SOCKET_CLOSED); | |
664 | |
665 // Note: don't use CancelIo to cancel pending IO because it doesn't work | |
666 // when there is a Winsock layered service provider. | |
667 | |
668 // In most socket implementations, closing a socket results in a graceful | |
669 // connection shutdown, but in Winsock we have to call shutdown explicitly. | |
670 // See the MSDN page "Graceful Shutdown, Linger Options, and Socket Closure" | |
671 // at http://msdn.microsoft.com/en-us/library/ms738547.aspx | |
672 shutdown(socket_, SD_SEND); | |
673 | |
674 // This cancels any pending IO. | |
675 if (closesocket(socket_) < 0) | |
676 PLOG(ERROR) << "closesocket"; | |
677 socket_ = INVALID_SOCKET; | |
678 } | |
679 | |
680 if (!accept_callback_.is_null()) { | |
681 accept_watcher_.StopWatching(); | |
682 accept_socket_ = NULL; | |
683 accept_address_ = NULL; | |
684 accept_callback_.Reset(); | |
685 } | |
686 | |
687 if (accept_event_) { | |
688 WSACloseEvent(accept_event_); | |
689 accept_event_ = WSA_INVALID_EVENT; | |
690 } | |
691 | |
692 if (core_.get()) { | |
693 if (waiting_connect_) { | |
694 // We closed the socket, so this notification will never come. | |
695 // From MSDN' WSAEventSelect documentation: | |
696 // "Closing a socket with closesocket also cancels the association and | |
697 // selection of network events specified in WSAEventSelect for the | |
698 // socket". | |
699 core_->Release(); | |
700 } | |
701 core_->Detach(); | |
702 core_ = NULL; | |
703 } | |
704 | |
705 waiting_connect_ = false; | |
706 waiting_read_ = false; | |
707 waiting_write_ = false; | |
708 | |
709 read_callback_.Reset(); | |
710 write_callback_.Reset(); | |
711 peer_address_.reset(); | |
712 connect_os_error_ = 0; | |
713 } | |
714 | |
715 void TCPSocketWin::StartLoggingMultipleConnectAttempts( | |
716 const AddressList& addresses) { | |
717 if (!logging_multiple_connect_attempts_) { | |
718 logging_multiple_connect_attempts_ = true; | |
719 LogConnectBegin(addresses); | |
720 } else { | |
721 NOTREACHED(); | |
722 } | |
723 } | |
724 | |
725 void TCPSocketWin::EndLoggingMultipleConnectAttempts(int net_error) { | |
726 if (logging_multiple_connect_attempts_) { | |
727 LogConnectEnd(net_error); | |
728 logging_multiple_connect_attempts_ = false; | |
729 } else { | |
730 NOTREACHED(); | |
731 } | |
732 } | |
733 | |
734 int TCPSocketWin::AcceptInternal(scoped_ptr<TCPSocketWin>* socket, | |
735 IPEndPoint* address) { | |
736 SockaddrStorage storage; | |
737 int new_socket = accept(socket_, storage.addr, &storage.addr_len); | |
738 if (new_socket < 0) { | |
739 int net_error = MapSystemError(WSAGetLastError()); | |
740 if (net_error != ERR_IO_PENDING) | |
741 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, net_error); | |
742 return net_error; | |
743 } | |
744 | |
745 IPEndPoint ip_end_point; | |
746 if (!ip_end_point.FromSockAddr(storage.addr, storage.addr_len)) { | |
747 NOTREACHED(); | |
748 if (closesocket(new_socket) < 0) | |
749 PLOG(ERROR) << "closesocket"; | |
750 int net_error = ERR_ADDRESS_INVALID; | |
751 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, net_error); | |
752 return net_error; | |
753 } | |
754 scoped_ptr<TCPSocketWin> tcp_socket(new TCPSocketWin( | |
755 net_log_.net_log(), net_log_.source())); | |
756 int adopt_result = tcp_socket->AdoptConnectedSocket(new_socket, ip_end_point); | |
757 if (adopt_result != OK) { | |
758 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, adopt_result); | |
759 return adopt_result; | |
760 } | |
761 *socket = tcp_socket.Pass(); | |
762 *address = ip_end_point; | |
763 net_log_.EndEvent(NetLog::TYPE_TCP_ACCEPT, | |
764 CreateNetLogIPEndPointCallback(&ip_end_point)); | |
765 return OK; | |
766 } | |
767 | |
768 void TCPSocketWin::OnObjectSignaled(HANDLE object) { | |
769 // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is fixed. | |
770 tracked_objects::ScopedTracker tracking_profile( | |
771 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
772 "418383 TCPSocketWin::OnObjectSignaled")); | |
773 | |
774 WSANETWORKEVENTS ev; | |
775 if (WSAEnumNetworkEvents(socket_, accept_event_, &ev) == SOCKET_ERROR) { | |
776 PLOG(ERROR) << "WSAEnumNetworkEvents()"; | |
777 return; | |
778 } | |
779 | |
780 if (ev.lNetworkEvents & FD_ACCEPT) { | |
781 int result = AcceptInternal(accept_socket_, accept_address_); | |
782 if (result != ERR_IO_PENDING) { | |
783 accept_socket_ = NULL; | |
784 accept_address_ = NULL; | |
785 base::ResetAndReturn(&accept_callback_).Run(result); | |
786 } | |
787 } else { | |
788 // This happens when a client opens a connection and closes it before we | |
789 // have a chance to accept it. | |
790 DCHECK(ev.lNetworkEvents == 0); | |
791 | |
792 // Start watching the next FD_ACCEPT event. | |
793 WSAEventSelect(socket_, accept_event_, FD_ACCEPT); | |
794 accept_watcher_.StartWatching(accept_event_, this); | |
795 } | |
796 } | |
797 | |
798 int TCPSocketWin::DoConnect() { | |
799 // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. | |
800 tracked_objects::ScopedTracker tracking_profile( | |
801 FROM_HERE_WITH_EXPLICIT_FUNCTION("436634 TCPSocketWin::DoConnect")); | |
802 | |
803 DCHECK_EQ(connect_os_error_, 0); | |
804 DCHECK(!core_.get()); | |
805 | |
806 net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT, | |
807 CreateNetLogIPEndPointCallback(peer_address_.get())); | |
808 | |
809 core_ = new Core(this); | |
810 | |
811 // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. | |
812 tracked_objects::ScopedTracker tracking_profile1( | |
813 FROM_HERE_WITH_EXPLICIT_FUNCTION("436634 TCPSocketWin::DoConnect1")); | |
814 | |
815 // WSAEventSelect sets the socket to non-blocking mode as a side effect. | |
816 // Our connect() and recv() calls require that the socket be non-blocking. | |
817 WSAEventSelect(socket_, core_->read_overlapped_.hEvent, FD_CONNECT); | |
818 | |
819 SockaddrStorage storage; | |
820 if (!peer_address_->ToSockAddr(storage.addr, &storage.addr_len)) | |
821 return ERR_ADDRESS_INVALID; | |
822 | |
823 // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. | |
824 tracked_objects::ScopedTracker tracking_profile2( | |
825 FROM_HERE_WITH_EXPLICIT_FUNCTION("436634 TCPSocketWin::DoConnect2")); | |
826 | |
827 if (!connect(socket_, storage.addr, storage.addr_len)) { | |
828 // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. | |
829 tracked_objects::ScopedTracker tracking_profile3( | |
830 FROM_HERE_WITH_EXPLICIT_FUNCTION("436634 TCPSocketWin::DoConnect3")); | |
831 | |
832 // Connected without waiting! | |
833 // | |
834 // The MSDN page for connect says: | |
835 // With a nonblocking socket, the connection attempt cannot be completed | |
836 // immediately. In this case, connect will return SOCKET_ERROR, and | |
837 // WSAGetLastError will return WSAEWOULDBLOCK. | |
838 // which implies that for a nonblocking socket, connect never returns 0. | |
839 // It's not documented whether the event object will be signaled or not | |
840 // if connect does return 0. So the code below is essentially dead code | |
841 // and we don't know if it's correct. | |
842 NOTREACHED(); | |
843 | |
844 if (ResetEventIfSignaled(core_->read_overlapped_.hEvent)) | |
845 return OK; | |
846 } else { | |
847 int os_error = WSAGetLastError(); | |
848 | |
849 // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. | |
850 tracked_objects::ScopedTracker tracking_profile4( | |
851 FROM_HERE_WITH_EXPLICIT_FUNCTION("436634 TCPSocketWin::DoConnect4")); | |
852 | |
853 if (os_error != WSAEWOULDBLOCK) { | |
854 LOG(ERROR) << "connect failed: " << os_error; | |
855 connect_os_error_ = os_error; | |
856 int rv = MapConnectError(os_error); | |
857 CHECK_NE(ERR_IO_PENDING, rv); | |
858 return rv; | |
859 } | |
860 } | |
861 | |
862 // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. | |
863 tracked_objects::ScopedTracker tracking_profile5( | |
864 FROM_HERE_WITH_EXPLICIT_FUNCTION("436634 TCPSocketWin::DoConnect5")); | |
865 | |
866 core_->WatchForRead(); | |
867 return ERR_IO_PENDING; | |
868 } | |
869 | |
870 void TCPSocketWin::DoConnectComplete(int result) { | |
871 // Log the end of this attempt (and any OS error it threw). | |
872 int os_error = connect_os_error_; | |
873 connect_os_error_ = 0; | |
874 if (result != OK) { | |
875 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT, | |
876 NetLog::IntegerCallback("os_error", os_error)); | |
877 } else { | |
878 net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT); | |
879 } | |
880 | |
881 if (!logging_multiple_connect_attempts_) | |
882 LogConnectEnd(result); | |
883 } | |
884 | |
885 void TCPSocketWin::LogConnectBegin(const AddressList& addresses) { | |
886 net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT, | |
887 addresses.CreateNetLogCallback()); | |
888 } | |
889 | |
890 void TCPSocketWin::LogConnectEnd(int net_error) { | |
891 if (net_error == OK) | |
892 UpdateConnectionTypeHistograms(CONNECTION_ANY); | |
893 | |
894 if (net_error != OK) { | |
895 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT, net_error); | |
896 return; | |
897 } | |
898 | |
899 struct sockaddr_storage source_address; | |
900 socklen_t addrlen = sizeof(source_address); | |
901 int rv = getsockname( | |
902 socket_, reinterpret_cast<struct sockaddr*>(&source_address), &addrlen); | |
903 if (rv != 0) { | |
904 LOG(ERROR) << "getsockname() [rv: " << rv | |
905 << "] error: " << WSAGetLastError(); | |
906 NOTREACHED(); | |
907 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_CONNECT, rv); | |
908 return; | |
909 } | |
910 | |
911 net_log_.EndEvent( | |
912 NetLog::TYPE_TCP_CONNECT, | |
913 CreateNetLogSourceAddressCallback( | |
914 reinterpret_cast<const struct sockaddr*>(&source_address), | |
915 sizeof(source_address))); | |
916 } | |
917 | |
918 int TCPSocketWin::DoRead(IOBuffer* buf, int buf_len, | |
919 const CompletionCallback& callback) { | |
920 if (!core_->non_blocking_reads_initialized_) { | |
921 WSAEventSelect(socket_, core_->read_overlapped_.hEvent, | |
922 FD_READ | FD_CLOSE); | |
923 core_->non_blocking_reads_initialized_ = true; | |
924 } | |
925 int rv = recv(socket_, buf->data(), buf_len, 0); | |
926 if (rv == SOCKET_ERROR) { | |
927 int os_error = WSAGetLastError(); | |
928 if (os_error != WSAEWOULDBLOCK) { | |
929 int net_error = MapSystemError(os_error); | |
930 net_log_.AddEvent( | |
931 NetLog::TYPE_SOCKET_READ_ERROR, | |
932 CreateNetLogSocketErrorCallback(net_error, os_error)); | |
933 return net_error; | |
934 } | |
935 } else { | |
936 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, rv, | |
937 buf->data()); | |
938 NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(rv); | |
939 return rv; | |
940 } | |
941 | |
942 waiting_read_ = true; | |
943 read_callback_ = callback; | |
944 core_->read_iobuffer_ = buf; | |
945 core_->read_buffer_length_ = buf_len; | |
946 core_->WatchForRead(); | |
947 return ERR_IO_PENDING; | |
948 } | |
949 | |
950 void TCPSocketWin::DidCompleteConnect() { | |
951 DCHECK(waiting_connect_); | |
952 DCHECK(!read_callback_.is_null()); | |
953 int result; | |
954 | |
955 // TODO(pkasting): Remove ScopedTracker below once crbug.com/418183 is fixed. | |
956 tracked_objects::ScopedTracker tracking_profile1( | |
957 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
958 "418183 TCPSocketWin::DidCompleteConnect1")); | |
959 WSANETWORKEVENTS events; | |
960 int rv = WSAEnumNetworkEvents(socket_, core_->read_overlapped_.hEvent, | |
961 &events); | |
962 int os_error = 0; | |
963 if (rv == SOCKET_ERROR) { | |
964 NOTREACHED(); | |
965 os_error = WSAGetLastError(); | |
966 result = MapSystemError(os_error); | |
967 } else if (events.lNetworkEvents & FD_CONNECT) { | |
968 // TODO(pkasting): Remove ScopedTracker below once crbug.com/418183 is | |
969 // fixed. | |
970 tracked_objects::ScopedTracker tracking_profile2( | |
971 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
972 "418183 TCPSocketWin::DidCompleteConnect2")); | |
973 os_error = events.iErrorCode[FD_CONNECT_BIT]; | |
974 result = MapConnectError(os_error); | |
975 } else { | |
976 NOTREACHED(); | |
977 result = ERR_UNEXPECTED; | |
978 } | |
979 | |
980 // TODO(pkasting): Remove ScopedTracker below once crbug.com/418183 is fixed. | |
981 tracked_objects::ScopedTracker tracking_profile3( | |
982 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
983 "418183 TCPSocketWin::DidCompleteConnect3")); | |
984 connect_os_error_ = os_error; | |
985 DoConnectComplete(result); | |
986 waiting_connect_ = false; | |
987 | |
988 // TODO(pkasting): Remove ScopedTracker below once crbug.com/418183 is fixed. | |
989 tracked_objects::ScopedTracker tracking_profile4( | |
990 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
991 "418183 TCPSocketWin::DidCompleteConnect4")); | |
992 DCHECK_NE(result, ERR_IO_PENDING); | |
993 base::ResetAndReturn(&read_callback_).Run(result); | |
994 } | |
995 | |
996 void TCPSocketWin::DidCompleteWrite() { | |
997 DCHECK(waiting_write_); | |
998 DCHECK(!write_callback_.is_null()); | |
999 | |
1000 DWORD num_bytes, flags; | |
1001 BOOL ok = WSAGetOverlappedResult(socket_, &core_->write_overlapped_, | |
1002 &num_bytes, FALSE, &flags); | |
1003 WSAResetEvent(core_->write_overlapped_.hEvent); | |
1004 waiting_write_ = false; | |
1005 int rv; | |
1006 if (!ok) { | |
1007 int os_error = WSAGetLastError(); | |
1008 rv = MapSystemError(os_error); | |
1009 net_log_.AddEvent(NetLog::TYPE_SOCKET_WRITE_ERROR, | |
1010 CreateNetLogSocketErrorCallback(rv, os_error)); | |
1011 } else { | |
1012 rv = static_cast<int>(num_bytes); | |
1013 if (rv > core_->write_buffer_length_ || rv < 0) { | |
1014 // It seems that some winsock interceptors report that more was written | |
1015 // than was available. Treat this as an error. http://crbug.com/27870 | |
1016 LOG(ERROR) << "Detected broken LSP: Asked to write " | |
1017 << core_->write_buffer_length_ << " bytes, but " << rv | |
1018 << " bytes reported."; | |
1019 rv = ERR_WINSOCK_UNEXPECTED_WRITTEN_BYTES; | |
1020 } else { | |
1021 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, num_bytes, | |
1022 core_->write_iobuffer_->data()); | |
1023 NetworkActivityMonitor::GetInstance()->IncrementBytesSent(num_bytes); | |
1024 } | |
1025 } | |
1026 | |
1027 core_->write_iobuffer_ = NULL; | |
1028 | |
1029 DCHECK_NE(rv, ERR_IO_PENDING); | |
1030 base::ResetAndReturn(&write_callback_).Run(rv); | |
1031 } | |
1032 | |
1033 void TCPSocketWin::DidSignalRead() { | |
1034 DCHECK(waiting_read_); | |
1035 DCHECK(!read_callback_.is_null()); | |
1036 | |
1037 // TODO(pkasting): Remove ScopedTracker below once crbug.com/418183 is fixed. | |
1038 tracked_objects::ScopedTracker tracking_profile1( | |
1039 FROM_HERE_WITH_EXPLICIT_FUNCTION("418183 TCPSocketWin::DidSignalRead1")); | |
1040 int os_error = 0; | |
1041 WSANETWORKEVENTS network_events; | |
1042 int rv = WSAEnumNetworkEvents(socket_, core_->read_overlapped_.hEvent, | |
1043 &network_events); | |
1044 if (rv == SOCKET_ERROR) { | |
1045 os_error = WSAGetLastError(); | |
1046 rv = MapSystemError(os_error); | |
1047 } else if (network_events.lNetworkEvents) { | |
1048 // TODO(pkasting): Remove ScopedTracker below once crbug.com/418183 is | |
1049 // fixed. | |
1050 tracked_objects::ScopedTracker tracking_profile2( | |
1051 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
1052 "418183 TCPSocketWin::DidSignalRead2")); | |
1053 DCHECK_EQ(network_events.lNetworkEvents & ~(FD_READ | FD_CLOSE), 0); | |
1054 // If network_events.lNetworkEvents is FD_CLOSE and | |
1055 // network_events.iErrorCode[FD_CLOSE_BIT] is 0, it is a graceful | |
1056 // connection closure. It is tempting to directly set rv to 0 in | |
1057 // this case, but the MSDN pages for WSAEventSelect and | |
1058 // WSAAsyncSelect recommend we still call DoRead(): | |
1059 // FD_CLOSE should only be posted after all data is read from a | |
1060 // socket, but an application should check for remaining data upon | |
1061 // receipt of FD_CLOSE to avoid any possibility of losing data. | |
1062 // | |
1063 // If network_events.iErrorCode[FD_READ_BIT] or | |
1064 // network_events.iErrorCode[FD_CLOSE_BIT] is nonzero, still call | |
1065 // DoRead() because recv() reports a more accurate error code | |
1066 // (WSAECONNRESET vs. WSAECONNABORTED) when the connection was | |
1067 // reset. | |
1068 rv = DoRead(core_->read_iobuffer_.get(), core_->read_buffer_length_, | |
1069 read_callback_); | |
1070 if (rv == ERR_IO_PENDING) | |
1071 return; | |
1072 } else { | |
1073 // TODO(pkasting): Remove ScopedTracker below once crbug.com/418183 is | |
1074 // fixed. | |
1075 tracked_objects::ScopedTracker tracking_profile3( | |
1076 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
1077 "418183 TCPSocketWin::DidSignalRead3")); | |
1078 // This may happen because Read() may succeed synchronously and | |
1079 // consume all the received data without resetting the event object. | |
1080 core_->WatchForRead(); | |
1081 return; | |
1082 } | |
1083 | |
1084 waiting_read_ = false; | |
1085 core_->read_iobuffer_ = NULL; | |
1086 core_->read_buffer_length_ = 0; | |
1087 | |
1088 // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is fixed. | |
1089 tracked_objects::ScopedTracker tracking_profile4( | |
1090 FROM_HERE_WITH_EXPLICIT_FUNCTION("418183 TCPSocketWin::DidSignalRead4")); | |
1091 DCHECK_NE(rv, ERR_IO_PENDING); | |
1092 base::ResetAndReturn(&read_callback_).Run(rv); | |
1093 } | |
1094 | |
1095 } // namespace net | |
OLD | NEW |