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

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_client_socket.cc ('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"
10 #include "net/base/ip_endpoint.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"
11 #include "net/base/net_errors.h" 16 #include "net/base/net_errors.h"
12 #include "net/base/net_util.h" 17 #include "net/base/net_util.h"
18 #include "net/base/network_change_notifier.h"
13 #include "net/base/winsock_init.h" 19 #include "net/base/winsock_init.h"
14 #include "net/base/winsock_util.h" 20 #include "net/base/winsock_util.h"
15 #include "net/socket/socket_descriptor.h" 21 #include "net/socket/socket_descriptor.h"
16 #include "net/socket/socket_net_log_params.h" 22 #include "net/socket/socket_net_log_params.h"
17 23
18 namespace net { 24 namespace net {
19 25
26 namespace {
27
28 const int kTCPKeepAliveSeconds = 45;
29
30 bool SetSocketReceiveBufferSize(SOCKET socket, int32 size) {
31 int rv = setsockopt(socket, SOL_SOCKET, SO_RCVBUF,
32 reinterpret_cast<const char*>(&size), sizeof(size));
33 DCHECK(!rv) << "Could not set socket receive buffer size: " << GetLastError();
34 return rv == 0;
35 }
36
37 bool SetSocketSendBufferSize(SOCKET socket, int32 size) {
38 int rv = setsockopt(socket, SOL_SOCKET, SO_SNDBUF,
39 reinterpret_cast<const char*>(&size), sizeof(size));
40 DCHECK(!rv) << "Could not set socket send buffer size: " << GetLastError();
41 return rv == 0;
42 }
43
44 // Disable Nagle.
45 // The Nagle implementation on windows is governed by RFC 896. The idea
46 // behind Nagle is to reduce small packets on the network. When Nagle is
47 // enabled, if a partial packet has been sent, the TCP stack will disallow
48 // further *partial* packets until an ACK has been received from the other
49 // side. Good applications should always strive to send as much data as
50 // possible and avoid partial-packet sends. However, in most real world
51 // applications, there are edge cases where this does not happen, and two
52 // partial packets may be sent back to back. For a browser, it is NEVER
53 // a benefit to delay for an RTT before the second packet is sent.
54 //
55 // As a practical example in Chromium today, consider the case of a small
56 // POST. I have verified this:
57 // Client writes 649 bytes of header (partial packet #1)
58 // Client writes 50 bytes of POST data (partial packet #2)
59 // In the above example, with Nagle, a RTT delay is inserted between these
60 // two sends due to nagle. RTTs can easily be 100ms or more. The best
61 // fix is to make sure that for POSTing data, we write as much data as
62 // possible and minimize partial packets. We will fix that. But disabling
63 // Nagle also ensure we don't run into this delay in other edge cases.
64 // See also:
65 // http://technet.microsoft.com/en-us/library/bb726981.aspx
66 bool DisableNagle(SOCKET socket, bool disable) {
67 BOOL val = disable ? TRUE : FALSE;
68 int rv = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY,
69 reinterpret_cast<const char*>(&val),
70 sizeof(val));
71 DCHECK(!rv) << "Could not disable nagle";
72 return rv == 0;
73 }
74
75 // Enable TCP Keep-Alive to prevent NAT routers from timing out TCP
76 // connections. See http://crbug.com/27400 for details.
77 bool SetTCPKeepAlive(SOCKET socket, BOOL enable, int delay_secs) {
78 int delay = delay_secs * 1000;
79 struct tcp_keepalive keepalive_vals = {
80 enable ? 1 : 0, // TCP keep-alive on.
81 delay, // Delay seconds before sending first TCP keep-alive packet.
82 delay, // Delay seconds between sending TCP keep-alive packets.
83 };
84 DWORD bytes_returned = 0xABAB;
85 int rv = WSAIoctl(socket, SIO_KEEPALIVE_VALS, &keepalive_vals,
86 sizeof(keepalive_vals), NULL, 0,
87 &bytes_returned, NULL, NULL);
88 DCHECK(!rv) << "Could not enable TCP Keep-Alive for socket: " << socket
89 << " [error: " << WSAGetLastError() << "].";
90
91 // Disregard any failure in disabling nagle or enabling TCP Keep-Alive.
92 return rv == 0;
93 }
94
95 int MapConnectError(int os_error) {
96 switch (os_error) {
97 // connect fails with WSAEACCES when Windows Firewall blocks the
98 // connection.
99 case WSAEACCES:
100 return ERR_NETWORK_ACCESS_DENIED;
101 case WSAETIMEDOUT:
102 return ERR_CONNECTION_TIMED_OUT;
103 default: {
104 int net_error = MapSystemError(os_error);
105 if (net_error == ERR_FAILED)
106 return ERR_CONNECTION_FAILED; // More specific than ERR_FAILED.
107
108 // Give a more specific error when the user is offline.
109 if (net_error == ERR_ADDRESS_UNREACHABLE &&
110 NetworkChangeNotifier::IsOffline()) {
111 return ERR_INTERNET_DISCONNECTED;
112 }
113
114 return net_error;
115 }
116 }
117 }
118
119 } // namespace
120
121 //-----------------------------------------------------------------------------
122
123 // This class encapsulates all the state that has to be preserved as long as
124 // there is a network IO operation in progress. If the owner TCPSocketWin is
125 // destroyed while an operation is in progress, the Core is detached and it
126 // lives until the operation completes and the OS doesn't reference any resource
127 // declared on this class anymore.
128 class TCPSocketWin::Core : public base::RefCounted<Core> {
129 public:
130 explicit Core(TCPSocketWin* socket);
131
132 // Start watching for the end of a read or write operation.
133 void WatchForRead();
134 void WatchForWrite();
135
136 // The TCPSocketWin is going away.
137 void Detach() { socket_ = NULL; }
138
139 // The separate OVERLAPPED variables for asynchronous operation.
140 // |read_overlapped_| is used for both Connect() and Read().
141 // |write_overlapped_| is only used for Write();
142 OVERLAPPED read_overlapped_;
143 OVERLAPPED write_overlapped_;
144
145 // The buffers used in Read() and Write().
146 scoped_refptr<IOBuffer> read_iobuffer_;
147 scoped_refptr<IOBuffer> write_iobuffer_;
148 int read_buffer_length_;
149 int write_buffer_length_;
150
151 bool non_blocking_reads_initialized_;
152
153 private:
154 friend class base::RefCounted<Core>;
155
156 class ReadDelegate : public base::win::ObjectWatcher::Delegate {
157 public:
158 explicit ReadDelegate(Core* core) : core_(core) {}
159 virtual ~ReadDelegate() {}
160
161 // base::ObjectWatcher::Delegate methods:
162 virtual void OnObjectSignaled(HANDLE object);
163
164 private:
165 Core* const core_;
166 };
167
168 class WriteDelegate : public base::win::ObjectWatcher::Delegate {
169 public:
170 explicit WriteDelegate(Core* core) : core_(core) {}
171 virtual ~WriteDelegate() {}
172
173 // base::ObjectWatcher::Delegate methods:
174 virtual void OnObjectSignaled(HANDLE object);
175
176 private:
177 Core* const core_;
178 };
179
180 ~Core();
181
182 // The socket that created this object.
183 TCPSocketWin* socket_;
184
185 // |reader_| handles the signals from |read_watcher_|.
186 ReadDelegate reader_;
187 // |writer_| handles the signals from |write_watcher_|.
188 WriteDelegate writer_;
189
190 // |read_watcher_| watches for events from Connect() and Read().
191 base::win::ObjectWatcher read_watcher_;
192 // |write_watcher_| watches for events from Write();
193 base::win::ObjectWatcher write_watcher_;
194
195 DISALLOW_COPY_AND_ASSIGN(Core);
196 };
197
198 TCPSocketWin::Core::Core(TCPSocketWin* socket)
199 : read_buffer_length_(0),
200 write_buffer_length_(0),
201 non_blocking_reads_initialized_(false),
202 socket_(socket),
203 reader_(this),
204 writer_(this) {
205 memset(&read_overlapped_, 0, sizeof(read_overlapped_));
206 memset(&write_overlapped_, 0, sizeof(write_overlapped_));
207
208 read_overlapped_.hEvent = WSACreateEvent();
209 write_overlapped_.hEvent = WSACreateEvent();
210 }
211
212 TCPSocketWin::Core::~Core() {
213 // Make sure the message loop is not watching this object anymore.
214 read_watcher_.StopWatching();
215 write_watcher_.StopWatching();
216
217 WSACloseEvent(read_overlapped_.hEvent);
218 memset(&read_overlapped_, 0xaf, sizeof(read_overlapped_));
219 WSACloseEvent(write_overlapped_.hEvent);
220 memset(&write_overlapped_, 0xaf, sizeof(write_overlapped_));
221 }
222
223 void TCPSocketWin::Core::WatchForRead() {
224 // We grab an extra reference because there is an IO operation in progress.
225 // Balanced in ReadDelegate::OnObjectSignaled().
226 AddRef();
227 read_watcher_.StartWatching(read_overlapped_.hEvent, &reader_);
228 }
229
230 void TCPSocketWin::Core::WatchForWrite() {
231 // We grab an extra reference because there is an IO operation in progress.
232 // Balanced in WriteDelegate::OnObjectSignaled().
233 AddRef();
234 write_watcher_.StartWatching(write_overlapped_.hEvent, &writer_);
235 }
236
237 void TCPSocketWin::Core::ReadDelegate::OnObjectSignaled(HANDLE object) {
238 DCHECK_EQ(object, core_->read_overlapped_.hEvent);
239 if (core_->socket_) {
240 if (core_->socket_->waiting_connect_)
241 core_->socket_->DidCompleteConnect();
242 else
243 core_->socket_->DidSignalRead();
244 }
245
246 core_->Release();
247 }
248
249 void TCPSocketWin::Core::WriteDelegate::OnObjectSignaled(
250 HANDLE object) {
251 DCHECK_EQ(object, core_->write_overlapped_.hEvent);
252 if (core_->socket_)
253 core_->socket_->DidCompleteWrite();
254
255 core_->Release();
256 }
257
258 //-----------------------------------------------------------------------------
259
20 TCPSocketWin::TCPSocketWin(net::NetLog* net_log, 260 TCPSocketWin::TCPSocketWin(net::NetLog* net_log,
21 const net::NetLog::Source& source) 261 const net::NetLog::Source& source)
22 : socket_(INVALID_SOCKET), 262 : socket_(INVALID_SOCKET),
23 socket_event_(WSA_INVALID_EVENT), 263 accept_event_(WSA_INVALID_EVENT),
24 accept_socket_(NULL), 264 accept_socket_(NULL),
25 accept_address_(NULL), 265 accept_address_(NULL),
266 waiting_connect_(false),
267 waiting_read_(false),
268 waiting_write_(false),
269 connect_os_error_(0),
270 logging_multiple_connect_attempts_(false),
26 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) { 271 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
27 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, 272 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
28 source.ToEventParametersCallback()); 273 source.ToEventParametersCallback());
29 EnsureWinsockInit(); 274 EnsureWinsockInit();
30 } 275 }
31 276
32 TCPSocketWin::~TCPSocketWin() { 277 TCPSocketWin::~TCPSocketWin() {
33 Close(); 278 Close();
34 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE); 279 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
35 } 280 }
36 281
37 int TCPSocketWin::Create(AddressFamily family) { 282 int TCPSocketWin::Open(AddressFamily family) {
38 DCHECK(CalledOnValidThread()); 283 DCHECK(CalledOnValidThread());
39 DCHECK_EQ(socket_, INVALID_SOCKET); 284 DCHECK_EQ(socket_, INVALID_SOCKET);
40 285
41 socket_ = CreatePlatformSocket(ConvertAddressFamily(family), SOCK_STREAM, 286 socket_ = CreatePlatformSocket(ConvertAddressFamily(family), SOCK_STREAM,
42 IPPROTO_TCP); 287 IPPROTO_TCP);
43 if (socket_ == INVALID_SOCKET) { 288 if (socket_ == INVALID_SOCKET) {
44 PLOG(ERROR) << "CreatePlatformSocket() returned an error"; 289 PLOG(ERROR) << "CreatePlatformSocket() returned an error";
45 return MapSystemError(WSAGetLastError()); 290 return MapSystemError(WSAGetLastError());
46 } 291 }
47 292
48 if (SetNonBlocking(socket_)) { 293 if (SetNonBlocking(socket_)) {
49 int result = MapSystemError(WSAGetLastError()); 294 int result = MapSystemError(WSAGetLastError());
50 Close(); 295 Close();
51 return result; 296 return result;
52 } 297 }
wtc 2013/09/12 21:31:07 I think we should move the creation of Core (core_
yzshen1 2013/09/12 21:45:10 Then we will need an additional boolean flag to ke
yzshen1 2013/09/13 06:39:07 I realized that we could still use |peer_address_|
53 298
54 return OK; 299 return OK;
55 } 300 }
56 301
57 int TCPSocketWin::Adopt(SOCKET socket) { 302 int TCPSocketWin::AdoptConnectedSocket(SOCKET socket,
303 const IPEndPoint& peer_address) {
58 DCHECK(CalledOnValidThread()); 304 DCHECK(CalledOnValidThread());
59 DCHECK_EQ(socket_, INVALID_SOCKET); 305 DCHECK_EQ(socket_, INVALID_SOCKET);
306 DCHECK(!core_);
60 307
61 socket_ = socket; 308 socket_ = socket;
62 309
63 if (SetNonBlocking(socket_)) { 310 if (SetNonBlocking(socket_)) {
64 int result = MapSystemError(WSAGetLastError()); 311 int result = MapSystemError(WSAGetLastError());
65 Close(); 312 Close();
66 return result; 313 return result;
67 } 314 }
68 315
316 core_ = new Core(this);
317 peer_address_ = peer_address;
318
69 return OK; 319 return OK;
70 } 320 }
71 321
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) { 322 int TCPSocketWin::Bind(const IPEndPoint& address) {
83 DCHECK(CalledOnValidThread()); 323 DCHECK(CalledOnValidThread());
84 DCHECK_NE(socket_, INVALID_SOCKET); 324 DCHECK_NE(socket_, INVALID_SOCKET);
85 325
86 SockaddrStorage storage; 326 SockaddrStorage storage;
87 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) 327 if (!address.ToSockAddr(storage.addr, &storage.addr_len))
88 return ERR_ADDRESS_INVALID; 328 return ERR_ADDRESS_INVALID;
89 329
90 int result = bind(socket_, storage.addr, storage.addr_len); 330 int result = bind(socket_, storage.addr, storage.addr_len);
91 if (result < 0) { 331 if (result < 0) {
92 PLOG(ERROR) << "bind() returned an error"; 332 PLOG(ERROR) << "bind() returned an error";
93 return MapSystemError(WSAGetLastError()); 333 return MapSystemError(WSAGetLastError());
94 } 334 }
95 335
96 return OK; 336 return OK;
97 } 337 }
98 338
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) { 339 int TCPSocketWin::Listen(int backlog) {
113 DCHECK(CalledOnValidThread()); 340 DCHECK(CalledOnValidThread());
114 DCHECK_GT(backlog, 0); 341 DCHECK_GT(backlog, 0);
115 DCHECK_NE(socket_, INVALID_SOCKET); 342 DCHECK_NE(socket_, INVALID_SOCKET);
116 DCHECK_EQ(socket_event_, WSA_INVALID_EVENT); 343 DCHECK_EQ(accept_event_, WSA_INVALID_EVENT);
117 344
118 socket_event_ = WSACreateEvent(); 345 accept_event_ = WSACreateEvent();
119 if (socket_event_ == WSA_INVALID_EVENT) { 346 if (accept_event_ == WSA_INVALID_EVENT) {
120 PLOG(ERROR) << "WSACreateEvent()"; 347 PLOG(ERROR) << "WSACreateEvent()";
121 return ERR_FAILED; 348 return MapSystemError(WSAGetLastError());
122 } 349 }
123 350
124 int result = listen(socket_, backlog); 351 int result = listen(socket_, backlog);
125 if (result < 0) { 352 if (result < 0) {
126 PLOG(ERROR) << "listen() returned an error"; 353 PLOG(ERROR) << "listen() returned an error";
127 result = MapSystemError(WSAGetLastError()); 354 return MapSystemError(WSAGetLastError());
128 return result;
129 } 355 }
130 356
131 return OK; 357 return OK;
132 } 358 }
133 359
134 int TCPSocketWin::Accept(scoped_ptr<TCPSocketWin>* socket, 360 int TCPSocketWin::Accept(scoped_ptr<TCPSocketWin>* socket,
135 IPEndPoint* address, 361 IPEndPoint* address,
136 const CompletionCallback& callback) { 362 const CompletionCallback& callback) {
137 DCHECK(CalledOnValidThread()); 363 DCHECK(CalledOnValidThread());
138 DCHECK(socket); 364 DCHECK(socket);
139 DCHECK(address); 365 DCHECK(address);
140 DCHECK(!callback.is_null()); 366 DCHECK(!callback.is_null());
141 DCHECK(accept_callback_.is_null()); 367 DCHECK(accept_callback_.is_null());
142 368
143 net_log_.BeginEvent(NetLog::TYPE_TCP_ACCEPT); 369 net_log_.BeginEvent(NetLog::TYPE_TCP_ACCEPT);
144 370
145 int result = AcceptInternal(socket, address); 371 int result = AcceptInternal(socket, address);
146 372
147 if (result == ERR_IO_PENDING) { 373 if (result == ERR_IO_PENDING) {
148 // Start watching. 374 // Start watching.
149 WSAEventSelect(socket_, socket_event_, FD_ACCEPT); 375 WSAEventSelect(socket_, accept_event_, FD_ACCEPT);
150 accept_watcher_.StartWatching(socket_event_, this); 376 accept_watcher_.StartWatching(accept_event_, this);
151 377
152 accept_socket_ = socket; 378 accept_socket_ = socket;
153 accept_address_ = address; 379 accept_address_ = address;
154 accept_callback_ = callback; 380 accept_callback_ = callback;
155 } 381 }
156 382
157 return result; 383 return result;
158 } 384 }
159 385
386 int TCPSocketWin::Connect(const IPEndPoint& address,
387 const CompletionCallback& callback) {
388 DCHECK(CalledOnValidThread());
389 DCHECK_NE(socket_, INVALID_SOCKET);
390 DCHECK(!waiting_connect_);
391
392 // |core_| will be non-NULL if Connect() has been called. Unless Close() is
393 // called to reset the internal state, a second call to Connect() is not
394 // allowed.
395 // Please note that we enforce this even if the previous Connect() has
396 // completed and failed. Although it is allowed to connect the same |socket_|
397 // again after a connection attempt failed on Windows, it results in
398 // unspecified behavior according to POSIX. Therefore, we make it behave in
399 // the same way as TCPSocketLibevent.
400 DCHECK(!core_);
401
402 if (!logging_multiple_connect_attempts_)
403 LogConnectBegin(AddressList(address));
404
405 peer_address_ = address;
406
407 int rv = DoConnect();
408 if (rv == ERR_IO_PENDING) {
409 // Synchronous operation not supported.
410 DCHECK(!callback.is_null());
411 read_callback_ = callback;
412 waiting_connect_ = true;
413 } else {
414 DoConnectComplete(rv);
415 }
416
417 return rv;
418 }
419
420 bool TCPSocketWin::IsConnected() const {
421 DCHECK(CalledOnValidThread());
422
423 if (socket_ == INVALID_SOCKET || waiting_connect_)
424 return false;
425
426 if (waiting_read_)
427 return true;
428
429 // Check if connection is alive.
430 char c;
431 int rv = recv(socket_, &c, 1, MSG_PEEK);
432 if (rv == 0)
433 return false;
434 if (rv == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK)
435 return false;
436
437 return true;
438 }
439
440 bool TCPSocketWin::IsConnectedAndIdle() const {
441 DCHECK(CalledOnValidThread());
442
443 if (socket_ == INVALID_SOCKET || waiting_connect_)
444 return false;
445
446 if (waiting_read_)
447 return true;
448
449 // Check if connection is alive and we haven't received any data
450 // unexpectedly.
451 char c;
452 int rv = recv(socket_, &c, 1, MSG_PEEK);
453 if (rv >= 0)
454 return false;
455 if (WSAGetLastError() != WSAEWOULDBLOCK)
456 return false;
457
458 return true;
459 }
460
461 int TCPSocketWin::Read(IOBuffer* buf,
462 int buf_len,
463 const CompletionCallback& callback) {
464 DCHECK(CalledOnValidThread());
465 DCHECK_NE(socket_, INVALID_SOCKET);
466 DCHECK(!waiting_read_);
467 DCHECK(read_callback_.is_null());
468 DCHECK(!core_->read_iobuffer_);
469
470 return DoRead(buf, buf_len, callback);
471 }
472
473 int TCPSocketWin::Write(IOBuffer* buf,
474 int buf_len,
475 const CompletionCallback& callback) {
476 DCHECK(CalledOnValidThread());
477 DCHECK_NE(socket_, INVALID_SOCKET);
478 DCHECK(!waiting_write_);
479 DCHECK(write_callback_.is_null());
480 DCHECK_GT(buf_len, 0);
481 DCHECK(!core_->write_iobuffer_);
482
483 base::StatsCounter writes("tcp.writes");
484 writes.Increment();
485
486 WSABUF write_buffer;
487 write_buffer.len = buf_len;
488 write_buffer.buf = buf->data();
489
490 // TODO(wtc): Remove the assertion after enough testing.
491 AssertEventNotSignaled(core_->write_overlapped_.hEvent);
492 DWORD num;
493 int rv = WSASend(socket_, &write_buffer, 1, &num, 0,
494 &core_->write_overlapped_, NULL);
495 if (rv == 0) {
496 if (ResetEventIfSignaled(core_->write_overlapped_.hEvent)) {
497 rv = static_cast<int>(num);
498 if (rv > buf_len || rv < 0) {
499 // It seems that some winsock interceptors report that more was written
500 // than was available. Treat this as an error. http://crbug.com/27870
501 LOG(ERROR) << "Detected broken LSP: Asked to write " << buf_len
502 << " bytes, but " << rv << " bytes reported.";
503 return ERR_WINSOCK_UNEXPECTED_WRITTEN_BYTES;
504 }
505 base::StatsCounter write_bytes("tcp.write_bytes");
506 write_bytes.Add(rv);
507 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, rv,
508 buf->data());
509 return rv;
510 }
511 } else {
512 int os_error = WSAGetLastError();
513 if (os_error != WSA_IO_PENDING) {
514 int net_error = MapSystemError(os_error);
515 net_log_.AddEvent(NetLog::TYPE_SOCKET_WRITE_ERROR,
516 CreateNetLogSocketErrorCallback(net_error, os_error));
517 return net_error;
518 }
519 }
520 waiting_write_ = true;
521 write_callback_ = callback;
522 core_->write_iobuffer_ = buf;
523 core_->write_buffer_length_ = buf_len;
524 core_->WatchForWrite();
525 return ERR_IO_PENDING;
526 }
527
528 int TCPSocketWin::GetLocalAddress(IPEndPoint* address) const {
529 DCHECK(CalledOnValidThread());
530 DCHECK(address);
531
532 SockaddrStorage storage;
533 if (getsockname(socket_, storage.addr, &storage.addr_len))
534 return MapSystemError(WSAGetLastError());
535 if (!address->FromSockAddr(storage.addr, storage.addr_len))
536 return ERR_ADDRESS_INVALID;
537
538 return OK;
539 }
540
541 int TCPSocketWin::GetPeerAddress(IPEndPoint* address) const {
542 DCHECK(CalledOnValidThread());
543 DCHECK(address);
544 if (!IsConnected())
545 return ERR_SOCKET_NOT_CONNECTED;
546 *address = peer_address_;
547 return OK;
548 }
549
160 int TCPSocketWin::SetDefaultOptionsForServer() { 550 int TCPSocketWin::SetDefaultOptionsForServer() {
161 return SetExclusiveAddrUse(); 551 return SetExclusiveAddrUse();
162 } 552 }
163 553
554 int TCPSocketWin::SetDefaultOptionsForClient() {
555 // Increase the socket buffer sizes from the default sizes for WinXP. In
556 // performance testing, there is substantial benefit by increasing from 8KB
557 // to 64KB.
558 // See also:
559 // http://support.microsoft.com/kb/823764/EN-US
560 // On Vista, if we manually set these sizes, Vista turns off its receive
561 // window auto-tuning feature.
562 // http://blogs.msdn.com/wndp/archive/2006/05/05/Winhec-blog-tcpip-2.aspx
563 // Since Vista's auto-tune is better than any static value we can could set,
564 // only change these on pre-vista machines.
565 if (base::win::GetVersion() < base::win::VERSION_VISTA) {
566 const int32 kSocketBufferSize = 64 * 1024;
567 SetSocketReceiveBufferSize(socket_, kSocketBufferSize);
568 SetSocketSendBufferSize(socket_, kSocketBufferSize);
569 }
570
571 DisableNagle(socket_, true);
572 SetTCPKeepAlive(socket_, true, kTCPKeepAliveSeconds);
573 return OK;
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() {
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;
wtc 2013/09/12 21:31:07 I suggest moving this block of code (lines 652-661
yzshen1 2013/09/12 21:45:10 (I am happy to make the change, just try to make s
662 }
663
664 waiting_connect_ = false;
665 waiting_read_ = false;
666 waiting_write_ = false;
667
668 read_callback_.Reset();
669 write_callback_.Reset();
wtc 2013/09/12 21:31:07 It is a little confusing that we seem to clean up
yzshen1 2013/09/12 21:45:10 Yeah, I think we could do more refactoring to move
670 peer_address_ = IPEndPoint();
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);
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_));
754
755 core_ = new Core(this);
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_client_socket.cc ('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