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