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

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

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

Powered by Google App Engine
This is Rietveld 408576698