| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 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_client_socket_win.h" | 5 #include "net/socket/tcp_client_socket_win.h" |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "base/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
| 9 #include "base/memory_debug.h" | 9 #include "base/memory_debug.h" |
| 10 #include "base/stats_counters.h" |
| 10 #include "base/string_util.h" | 11 #include "base/string_util.h" |
| 11 #include "base/sys_info.h" | 12 #include "base/sys_info.h" |
| 12 #include "base/trace_event.h" | 13 #include "base/trace_event.h" |
| 13 #include "net/base/io_buffer.h" | 14 #include "net/base/io_buffer.h" |
| 14 #include "net/base/net_errors.h" | 15 #include "net/base/net_errors.h" |
| 15 #include "net/base/winsock_init.h" | 16 #include "net/base/winsock_init.h" |
| 16 | 17 |
| 17 namespace net { | 18 namespace net { |
| 18 | 19 |
| 19 namespace { | 20 namespace { |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 232 | 233 |
| 233 TCPClientSocketWin::~TCPClientSocketWin() { | 234 TCPClientSocketWin::~TCPClientSocketWin() { |
| 234 Disconnect(); | 235 Disconnect(); |
| 235 } | 236 } |
| 236 | 237 |
| 237 int TCPClientSocketWin::Connect(CompletionCallback* callback) { | 238 int TCPClientSocketWin::Connect(CompletionCallback* callback) { |
| 238 // If already connected, then just return OK. | 239 // If already connected, then just return OK. |
| 239 if (socket_ != INVALID_SOCKET) | 240 if (socket_ != INVALID_SOCKET) |
| 240 return OK; | 241 return OK; |
| 241 | 242 |
| 243 static StatsCounter connects("tcp.connect"); |
| 244 connects.Increment(); |
| 245 |
| 242 TRACE_EVENT_BEGIN("socket.connect", this, ""); | 246 TRACE_EVENT_BEGIN("socket.connect", this, ""); |
| 243 const struct addrinfo* ai = current_ai_; | 247 const struct addrinfo* ai = current_ai_; |
| 244 DCHECK(ai); | 248 DCHECK(ai); |
| 245 | 249 |
| 246 int rv = CreateSocket(ai); | 250 int rv = CreateSocket(ai); |
| 247 if (rv != OK) | 251 if (rv != OK) |
| 248 return rv; | 252 return rv; |
| 249 | 253 |
| 250 DCHECK(!core_); | 254 DCHECK(!core_); |
| 251 core_ = new Core(this); | 255 core_ = new Core(this); |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 379 if (ResetEventIfSignaled(core_->read_overlapped_.hEvent)) { | 383 if (ResetEventIfSignaled(core_->read_overlapped_.hEvent)) { |
| 380 TRACE_EVENT_END("socket.read", this, StringPrintf("%d bytes", num)); | 384 TRACE_EVENT_END("socket.read", this, StringPrintf("%d bytes", num)); |
| 381 | 385 |
| 382 // Because of how WSARecv fills memory when used asynchronously, Purify | 386 // Because of how WSARecv fills memory when used asynchronously, Purify |
| 383 // isn't able to detect that it's been initialized, so it scans for 0xcd | 387 // isn't able to detect that it's been initialized, so it scans for 0xcd |
| 384 // in the buffer and reports UMRs (uninitialized memory reads) for those | 388 // in the buffer and reports UMRs (uninitialized memory reads) for those |
| 385 // individual bytes. We override that in PURIFY builds to avoid the | 389 // individual bytes. We override that in PURIFY builds to avoid the |
| 386 // false error reports. | 390 // false error reports. |
| 387 // See bug 5297. | 391 // See bug 5297. |
| 388 base::MemoryDebug::MarkAsInitialized(core_->read_buffer_.buf, num); | 392 base::MemoryDebug::MarkAsInitialized(core_->read_buffer_.buf, num); |
| 393 static StatsCounter read_bytes("tcp.read_bytes"); |
| 394 read_bytes.Add(num); |
| 389 return static_cast<int>(num); | 395 return static_cast<int>(num); |
| 390 } | 396 } |
| 391 } else { | 397 } else { |
| 392 int err = WSAGetLastError(); | 398 int err = WSAGetLastError(); |
| 393 if (err != WSA_IO_PENDING) | 399 if (err != WSA_IO_PENDING) |
| 394 return MapWinsockError(err); | 400 return MapWinsockError(err); |
| 395 } | 401 } |
| 396 core_->WatchForRead(); | 402 core_->WatchForRead(); |
| 397 waiting_read_ = true; | 403 waiting_read_ = true; |
| 398 read_callback_ = callback; | 404 read_callback_ = callback; |
| 399 core_->read_iobuffer_ = buf; | 405 core_->read_iobuffer_ = buf; |
| 400 return ERR_IO_PENDING; | 406 return ERR_IO_PENDING; |
| 401 } | 407 } |
| 402 | 408 |
| 403 int TCPClientSocketWin::Write(IOBuffer* buf, | 409 int TCPClientSocketWin::Write(IOBuffer* buf, |
| 404 int buf_len, | 410 int buf_len, |
| 405 CompletionCallback* callback) { | 411 CompletionCallback* callback) { |
| 406 DCHECK_NE(socket_, INVALID_SOCKET); | 412 DCHECK_NE(socket_, INVALID_SOCKET); |
| 407 DCHECK(!waiting_write_); | 413 DCHECK(!waiting_write_); |
| 408 DCHECK(!write_callback_); | 414 DCHECK(!write_callback_); |
| 409 DCHECK_GT(buf_len, 0); | 415 DCHECK_GT(buf_len, 0); |
| 410 DCHECK(!core_->write_iobuffer_); | 416 DCHECK(!core_->write_iobuffer_); |
| 411 | 417 |
| 418 static StatsCounter reads("tcp.writes"); |
| 419 reads.Increment(); |
| 420 |
| 412 core_->write_buffer_.len = buf_len; | 421 core_->write_buffer_.len = buf_len; |
| 413 core_->write_buffer_.buf = buf->data(); | 422 core_->write_buffer_.buf = buf->data(); |
| 414 | 423 |
| 415 TRACE_EVENT_BEGIN("socket.write", this, ""); | 424 TRACE_EVENT_BEGIN("socket.write", this, ""); |
| 416 // TODO(wtc): Remove the CHECK after enough testing. | 425 // TODO(wtc): Remove the CHECK after enough testing. |
| 417 CHECK( | 426 CHECK( |
| 418 WaitForSingleObject(core_->write_overlapped_.hEvent, 0) == WAIT_TIMEOUT); | 427 WaitForSingleObject(core_->write_overlapped_.hEvent, 0) == WAIT_TIMEOUT); |
| 419 DWORD num; | 428 DWORD num; |
| 420 int rv = WSASend(socket_, &core_->write_buffer_, 1, &num, 0, | 429 int rv = WSASend(socket_, &core_->write_buffer_, 1, &num, 0, |
| 421 &core_->write_overlapped_, NULL); | 430 &core_->write_overlapped_, NULL); |
| 422 if (rv == 0) { | 431 if (rv == 0) { |
| 423 if (ResetEventIfSignaled(core_->write_overlapped_.hEvent)) { | 432 if (ResetEventIfSignaled(core_->write_overlapped_.hEvent)) { |
| 424 TRACE_EVENT_END("socket.write", this, StringPrintf("%d bytes", num)); | 433 TRACE_EVENT_END("socket.write", this, StringPrintf("%d bytes", num)); |
| 434 static StatsCounter write_bytes("tcp.write_bytes"); |
| 435 write_bytes.Add(num); |
| 425 return static_cast<int>(num); | 436 return static_cast<int>(num); |
| 426 } | 437 } |
| 427 } else { | 438 } else { |
| 428 int err = WSAGetLastError(); | 439 int err = WSAGetLastError(); |
| 429 if (err != WSA_IO_PENDING) | 440 if (err != WSA_IO_PENDING) |
| 430 return MapWinsockError(err); | 441 return MapWinsockError(err); |
| 431 } | 442 } |
| 432 core_->WatchForWrite(); | 443 core_->WatchForWrite(); |
| 433 waiting_write_ = true; | 444 waiting_write_ = true; |
| 434 write_callback_ = callback; | 445 write_callback_ = callback; |
| 435 core_->write_iobuffer_ = buf; | 446 core_->write_iobuffer_ = buf; |
| 436 return ERR_IO_PENDING; | 447 return ERR_IO_PENDING; |
| 437 } | 448 } |
| 438 | 449 |
| 450 bool TCPClientSocketWin::SetReceiveBufferSize(int32 size) { |
| 451 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, |
| 452 reinterpret_cast<const char*>(&size), sizeof(size)); |
| 453 DCHECK(!rv) << "Could not set socket receive buffer size: " << GetLastError(); |
| 454 return rv == 0; |
| 455 } |
| 456 |
| 457 bool TCPClientSocketWin::SetSendBufferSize(int32 size) { |
| 458 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, |
| 459 reinterpret_cast<const char*>(&size), sizeof(size)); |
| 460 DCHECK(!rv) << "Could not set socket send buffer size: " << GetLastError(); |
| 461 return rv == 0; |
| 462 } |
| 463 |
| 439 int TCPClientSocketWin::CreateSocket(const struct addrinfo* ai) { | 464 int TCPClientSocketWin::CreateSocket(const struct addrinfo* ai) { |
| 440 socket_ = WSASocket(ai->ai_family, ai->ai_socktype, ai->ai_protocol, NULL, 0, | 465 socket_ = WSASocket(ai->ai_family, ai->ai_socktype, ai->ai_protocol, NULL, 0, |
| 441 WSA_FLAG_OVERLAPPED); | 466 WSA_FLAG_OVERLAPPED); |
| 442 if (socket_ == INVALID_SOCKET) { | 467 if (socket_ == INVALID_SOCKET) { |
| 443 DWORD err = WSAGetLastError(); | 468 DWORD err = WSAGetLastError(); |
| 444 LOG(ERROR) << "WSASocket failed: " << err; | 469 LOG(ERROR) << "WSASocket failed: " << err; |
| 445 return MapWinsockError(err); | 470 return MapWinsockError(err); |
| 446 } | 471 } |
| 447 | 472 |
| 448 // Increase the socket buffer sizes from the default sizes for WinXP. In | 473 // Increase the socket buffer sizes from the default sizes for WinXP. In |
| 449 // performance testing, there is substantial benefit by increasing from 8KB | 474 // performance testing, there is substantial benefit by increasing from 8KB |
| 450 // to 64KB. | 475 // to 64KB. |
| 451 // See also: | 476 // See also: |
| 452 // http://support.microsoft.com/kb/823764/EN-US | 477 // http://support.microsoft.com/kb/823764/EN-US |
| 453 // On Vista, if we manually set these sizes, Vista turns off its receive | 478 // On Vista, if we manually set these sizes, Vista turns off its receive |
| 454 // window auto-tuning feature. | 479 // window auto-tuning feature. |
| 455 // http://blogs.msdn.com/wndp/archive/2006/05/05/Winhec-blog-tcpip-2.aspx | 480 // http://blogs.msdn.com/wndp/archive/2006/05/05/Winhec-blog-tcpip-2.aspx |
| 456 // Since Vista's auto-tune is better than any static value we can could set, | 481 // Since Vista's auto-tune is better than any static value we can could set, |
| 457 // only change these on pre-vista machines. | 482 // only change these on pre-vista machines. |
| 458 int32 major_version, minor_version, fix_version; | 483 int32 major_version, minor_version, fix_version; |
| 459 base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version, | 484 base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version, |
| 460 &fix_version); | 485 &fix_version); |
| 461 if (major_version < 6) { | 486 if (major_version < 6) { |
| 462 const int kSocketBufferSize = 64 * 1024; | 487 const int32 kSocketBufferSize = 64 * 1024; |
| 463 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, | 488 SetReceiveBufferSize(kSocketBufferSize); |
| 464 reinterpret_cast<const char*>(&kSocketBufferSize), | 489 SetSendBufferSize(kSocketBufferSize); |
| 465 sizeof(kSocketBufferSize)); | |
| 466 DCHECK(!rv) << "Could not set socket send buffer size"; | |
| 467 rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, | |
| 468 reinterpret_cast<const char*>(&kSocketBufferSize), | |
| 469 sizeof(kSocketBufferSize)); | |
| 470 DCHECK(!rv) << "Could not set socket receive buffer size"; | |
| 471 } | 490 } |
| 472 | 491 |
| 473 // Disable Nagle. | 492 // Disable Nagle. |
| 474 // The Nagle implementation on windows is governed by RFC 896. The idea | 493 // The Nagle implementation on windows is governed by RFC 896. The idea |
| 475 // behind Nagle is to reduce small packets on the network. When Nagle is | 494 // behind Nagle is to reduce small packets on the network. When Nagle is |
| 476 // enabled, if a partial packet has been sent, the TCP stack will disallow | 495 // enabled, if a partial packet has been sent, the TCP stack will disallow |
| 477 // further *partial* packets until an ACK has been received from the other | 496 // further *partial* packets until an ACK has been received from the other |
| 478 // side. Good applications should always strive to send as much data as | 497 // side. Good applications should always strive to send as much data as |
| 479 // possible and avoid partial-packet sends. However, in most real world | 498 // possible and avoid partial-packet sends. However, in most real world |
| 480 // applications, there are edge cases where this does not happen, and two | 499 // applications, there are edge cases where this does not happen, and two |
| (...skipping 16 matching lines...) Expand all Loading... |
| 497 reinterpret_cast<const char*>(&kDisableNagle), sizeof(kDisableNagle)); | 516 reinterpret_cast<const char*>(&kDisableNagle), sizeof(kDisableNagle)); |
| 498 DCHECK(!rv) << "Could not disable nagle"; | 517 DCHECK(!rv) << "Could not disable nagle"; |
| 499 | 518 |
| 500 return OK; | 519 return OK; |
| 501 } | 520 } |
| 502 | 521 |
| 503 void TCPClientSocketWin::DoReadCallback(int rv) { | 522 void TCPClientSocketWin::DoReadCallback(int rv) { |
| 504 DCHECK_NE(rv, ERR_IO_PENDING); | 523 DCHECK_NE(rv, ERR_IO_PENDING); |
| 505 DCHECK(read_callback_); | 524 DCHECK(read_callback_); |
| 506 | 525 |
| 526 static StatsCounter read_bytes("tcp.read_bytes"); |
| 527 read_bytes.Add(rv); |
| 528 |
| 507 // since Run may result in Read being called, clear read_callback_ up front. | 529 // since Run may result in Read being called, clear read_callback_ up front. |
| 508 CompletionCallback* c = read_callback_; | 530 CompletionCallback* c = read_callback_; |
| 509 read_callback_ = NULL; | 531 read_callback_ = NULL; |
| 510 c->Run(rv); | 532 c->Run(rv); |
| 511 } | 533 } |
| 512 | 534 |
| 513 void TCPClientSocketWin::DoWriteCallback(int rv) { | 535 void TCPClientSocketWin::DoWriteCallback(int rv) { |
| 514 DCHECK_NE(rv, ERR_IO_PENDING); | 536 DCHECK_NE(rv, ERR_IO_PENDING); |
| 515 DCHECK(write_callback_); | 537 DCHECK(write_callback_); |
| 516 | 538 |
| 539 static StatsCounter write_bytes("tcp.write_bytes"); |
| 540 write_bytes.Add(rv); |
| 541 |
| 517 // since Run may result in Write being called, clear write_callback_ up front. | 542 // since Run may result in Write being called, clear write_callback_ up front. |
| 518 CompletionCallback* c = write_callback_; | 543 CompletionCallback* c = write_callback_; |
| 519 write_callback_ = NULL; | 544 write_callback_ = NULL; |
| 520 c->Run(rv); | 545 c->Run(rv); |
| 521 } | 546 } |
| 522 | 547 |
| 523 void TCPClientSocketWin::DidCompleteConnect() { | 548 void TCPClientSocketWin::DidCompleteConnect() { |
| 524 DCHECK(waiting_connect_); | 549 DCHECK(waiting_connect_); |
| 525 int result; | 550 int result; |
| 526 | 551 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 578 BOOL ok = WSAGetOverlappedResult(socket_, &core_->write_overlapped_, | 603 BOOL ok = WSAGetOverlappedResult(socket_, &core_->write_overlapped_, |
| 579 &num_bytes, FALSE, &flags); | 604 &num_bytes, FALSE, &flags); |
| 580 WSAResetEvent(core_->write_overlapped_.hEvent); | 605 WSAResetEvent(core_->write_overlapped_.hEvent); |
| 581 TRACE_EVENT_END("socket.write", this, StringPrintf("%d bytes", num_bytes)); | 606 TRACE_EVENT_END("socket.write", this, StringPrintf("%d bytes", num_bytes)); |
| 582 waiting_write_ = false; | 607 waiting_write_ = false; |
| 583 core_->write_iobuffer_ = NULL; | 608 core_->write_iobuffer_ = NULL; |
| 584 DoWriteCallback(ok ? num_bytes : MapWinsockError(WSAGetLastError())); | 609 DoWriteCallback(ok ? num_bytes : MapWinsockError(WSAGetLastError())); |
| 585 } | 610 } |
| 586 | 611 |
| 587 } // namespace net | 612 } // namespace net |
| OLD | NEW |