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

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

Issue 10309002: Reimplements net::AddressList without struct addrinfo. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added missing NET_EXPORT to *PortOnAddressList. Created 8 years, 7 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 <mstcpip.h> 7 #include <mstcpip.h>
8 8
9 #include "base/basictypes.h" 9 #include "base/basictypes.h"
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
11 #include "base/metrics/stats_counters.h" 11 #include "base/metrics/stats_counters.h"
12 #include "base/string_util.h" 12 #include "base/string_util.h"
13 #include "base/win/object_watcher.h" 13 #include "base/win/object_watcher.h"
14 #include "base/win/windows_version.h" 14 #include "base/win/windows_version.h"
15 #include "net/base/address_list_net_log_param.h" 15 #include "net/base/address_list_net_log_param.h"
16 #include "net/base/connection_type_histograms.h" 16 #include "net/base/connection_type_histograms.h"
17 #include "net/base/io_buffer.h" 17 #include "net/base/io_buffer.h"
18 #include "net/base/ip_endpoint.h" 18 #include "net/base/ip_endpoint.h"
19 #include "net/base/net_errors.h" 19 #include "net/base/net_errors.h"
20 #include "net/base/net_log.h" 20 #include "net/base/net_log.h"
21 #include "net/base/net_util.h" 21 #include "net/base/net_util.h"
22 #include "net/base/network_change_notifier.h" 22 #include "net/base/network_change_notifier.h"
23 #include "net/base/sys_addrinfo.h"
24 #include "net/base/winsock_init.h" 23 #include "net/base/winsock_init.h"
25 #include "net/base/winsock_util.h" 24 #include "net/base/winsock_util.h"
26 25
27 namespace net { 26 namespace net {
28 27
29 namespace { 28 namespace {
30 29
31 bool SetSocketReceiveBufferSize(SOCKET socket, int32 size) { 30 bool SetSocketReceiveBufferSize(SOCKET socket, int32 size) {
32 int rv = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, 31 int rv = setsockopt(socket, SOL_SOCKET, SO_RCVBUF,
33 reinterpret_cast<const char*>(&size), sizeof(size)); 32 reinterpret_cast<const char*>(&size), sizeof(size));
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 } 309 }
311 310
312 //----------------------------------------------------------------------------- 311 //-----------------------------------------------------------------------------
313 312
314 TCPClientSocketWin::TCPClientSocketWin(const AddressList& addresses, 313 TCPClientSocketWin::TCPClientSocketWin(const AddressList& addresses,
315 net::NetLog* net_log, 314 net::NetLog* net_log,
316 const net::NetLog::Source& source) 315 const net::NetLog::Source& source)
317 : socket_(INVALID_SOCKET), 316 : socket_(INVALID_SOCKET),
318 bound_socket_(INVALID_SOCKET), 317 bound_socket_(INVALID_SOCKET),
319 addresses_(addresses), 318 addresses_(addresses),
320 current_ai_(NULL), 319 current_address_index_(static_cast<size_t>(-1)),
321 waiting_read_(false), 320 waiting_read_(false),
322 waiting_write_(false), 321 waiting_write_(false),
323 next_connect_state_(CONNECT_STATE_NONE), 322 next_connect_state_(CONNECT_STATE_NONE),
324 connect_os_error_(0), 323 connect_os_error_(0),
325 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)), 324 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)),
326 previously_disconnected_(false), 325 previously_disconnected_(false),
327 num_bytes_read_(0) { 326 num_bytes_read_(0) {
328 scoped_refptr<NetLog::EventParameters> params; 327 scoped_refptr<NetLog::EventParameters> params;
329 if (source.is_valid()) 328 if (source.is_valid())
330 params = new NetLogSourceParameter("source_dependency", source); 329 params = new NetLogSourceParameter("source_dependency", source);
(...skipping 11 matching lines...) Expand all
342 341
343 int error = SetupSocket(socket); 342 int error = SetupSocket(socket);
344 if (error) 343 if (error)
345 return MapSystemError(error); 344 return MapSystemError(error);
346 345
347 socket_ = socket; 346 socket_ = socket;
348 SetNonBlocking(socket_); 347 SetNonBlocking(socket_);
349 348
350 core_ = new Core(this); 349 core_ = new Core(this);
351 350
352 current_ai_ = addresses_.head(); 351 current_address_index_ = 0;
353 use_history_.set_was_ever_connected(); 352 use_history_.set_was_ever_connected();
354 353
355 return OK; 354 return OK;
356 } 355 }
357 356
358 int TCPClientSocketWin::Bind(const IPEndPoint& address) { 357 int TCPClientSocketWin::Bind(const IPEndPoint& address) {
359 if (current_ai_ != NULL || bind_address_.get()) { 358 if (current_address_index_ < addresses_.size() || bind_address_.get()) {
360 // Cannot bind the socket if we are already connected or connecting. 359 // Cannot bind the socket if we are already connected or connecting.
361 return ERR_UNEXPECTED; 360 return ERR_UNEXPECTED;
362 } 361 }
363 362
364 sockaddr_storage addr_storage; 363 SockaddrStorage storage;
365 sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage); 364 if (!address.ToSockAddr(storage.addr, &storage.addr_len))
366 size_t addr_len = sizeof(addr_storage);
367 if (!address.ToSockAddr(addr, &addr_len))
368 return ERR_INVALID_ARGUMENT; 365 return ERR_INVALID_ARGUMENT;
369 366
370 // Create |bound_socket_| and try to bound it to |address|. 367 // Create |bound_socket_| and try to bound it to |address|.
371 int error = CreateSocket(address.GetFamily(), &bound_socket_); 368 int error = CreateSocket(address.GetFamily(), &bound_socket_);
372 if (error) 369 if (error)
373 return MapSystemError(error); 370 return MapSystemError(error);
374 371
375 if (bind(bound_socket_, addr, addr_len)) { 372 if (bind(bound_socket_, storage.addr, storage.addr_len)) {
376 error = errno; 373 error = errno;
377 if (closesocket(bound_socket_) < 0) 374 if (closesocket(bound_socket_) < 0)
378 PLOG(ERROR) << "closesocket"; 375 PLOG(ERROR) << "closesocket";
379 bound_socket_ = INVALID_SOCKET; 376 bound_socket_ = INVALID_SOCKET;
380 return MapSystemError(error); 377 return MapSystemError(error);
381 } 378 }
382 379
383 bind_address_.reset(new IPEndPoint(address)); 380 bind_address_.reset(new IPEndPoint(address));
384 381
385 return 0; 382 return 0;
386 } 383 }
387 384
388 385
389 int TCPClientSocketWin::Connect(const CompletionCallback& callback) { 386 int TCPClientSocketWin::Connect(const CompletionCallback& callback) {
390 DCHECK(CalledOnValidThread()); 387 DCHECK(CalledOnValidThread());
391 388
392 // If already connected, then just return OK. 389 // If already connected, then just return OK.
393 if (socket_ != INVALID_SOCKET) 390 if (socket_ != INVALID_SOCKET)
394 return OK; 391 return OK;
395 392
396 base::StatsCounter connects("tcp.connect"); 393 base::StatsCounter connects("tcp.connect");
397 connects.Increment(); 394 connects.Increment();
398 395
399 net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT, 396 net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT,
400 new AddressListNetLogParam(addresses_)); 397 new AddressListNetLogParam(addresses_));
401 398
402 // We will try to connect to each address in addresses_. Start with the 399 // We will try to connect to each address in addresses_. Start with the
403 // first one in the list. 400 // first one in the list.
404 next_connect_state_ = CONNECT_STATE_CONNECT; 401 next_connect_state_ = CONNECT_STATE_CONNECT;
405 current_ai_ = addresses_.head(); 402 current_address_index_ = 0;
406 403
407 int rv = DoConnectLoop(OK); 404 int rv = DoConnectLoop(OK);
408 if (rv == ERR_IO_PENDING) { 405 if (rv == ERR_IO_PENDING) {
409 // Synchronous operation not supported. 406 // Synchronous operation not supported.
410 DCHECK(!callback.is_null()); 407 DCHECK(!callback.is_null());
411 // TODO(ajwong): Is setting read_callback_ the right thing to do here?? 408 // TODO(ajwong): Is setting read_callback_ the right thing to do here??
412 read_callback_ = callback; 409 read_callback_ = callback;
413 } else { 410 } else {
414 LogConnectCompletion(rv); 411 LogConnectCompletion(rv);
415 } 412 }
(...skipping 20 matching lines...) Expand all
436 LOG(DFATAL) << "bad state " << state; 433 LOG(DFATAL) << "bad state " << state;
437 rv = ERR_UNEXPECTED; 434 rv = ERR_UNEXPECTED;
438 break; 435 break;
439 } 436 }
440 } while (rv != ERR_IO_PENDING && next_connect_state_ != CONNECT_STATE_NONE); 437 } while (rv != ERR_IO_PENDING && next_connect_state_ != CONNECT_STATE_NONE);
441 438
442 return rv; 439 return rv;
443 } 440 }
444 441
445 int TCPClientSocketWin::DoConnect() { 442 int TCPClientSocketWin::DoConnect() {
446 const struct addrinfo* ai = current_ai_; 443 DCHECK_LT(current_address_index_, addresses_.size());
447 DCHECK(ai);
448 DCHECK_EQ(0, connect_os_error_); 444 DCHECK_EQ(0, connect_os_error_);
449 445
446 const IPEndPoint& endpoint = addresses_[current_address_index_];
447
450 if (previously_disconnected_) { 448 if (previously_disconnected_) {
451 use_history_.Reset(); 449 use_history_.Reset();
452 previously_disconnected_ = false; 450 previously_disconnected_ = false;
453 } 451 }
454 452
455 net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT, 453 net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT,
456 new NetLogStringParameter( 454 new NetLogStringParameter("address",
457 "address", NetAddressToStringWithPort(current_ai_))); 455 endpoint.ToString()));
458 456
459 next_connect_state_ = CONNECT_STATE_CONNECT_COMPLETE; 457 next_connect_state_ = CONNECT_STATE_CONNECT_COMPLETE;
460 458
461 if (bound_socket_ != INVALID_SOCKET) { 459 if (bound_socket_ != INVALID_SOCKET) {
462 DCHECK(bind_address_.get()); 460 DCHECK(bind_address_.get());
463 socket_ = bound_socket_; 461 socket_ = bound_socket_;
464 bound_socket_ = INVALID_SOCKET; 462 bound_socket_ = INVALID_SOCKET;
465 } else { 463 } else {
466 connect_os_error_ = CreateSocket(ai->ai_family, &socket_); 464 connect_os_error_ = CreateSocket(endpoint.GetFamily(), &socket_);
eroman 2012/05/04 01:08:41 Side comment: When we refactor GetFamily() to retu
szym 2012/05/04 02:38:29 Yup. To avoid this pitfall when converting Request
467 if (connect_os_error_ != 0) 465 if (connect_os_error_ != 0)
468 return MapSystemError(connect_os_error_); 466 return MapSystemError(connect_os_error_);
469 467
470 if (bind_address_.get()) { 468 if (bind_address_.get()) {
471 sockaddr_storage addr_storage; 469 SockaddrStorage storage;
472 sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage); 470 if (!bind_address_->ToSockAddr(storage.addr, &storage.addr_len))
473 size_t addr_len = sizeof(addr_storage);
474 if (!bind_address_->ToSockAddr(addr, &addr_len))
475 return ERR_INVALID_ARGUMENT; 471 return ERR_INVALID_ARGUMENT;
476 if (bind(socket_, addr, addr_len)) 472 if (bind(socket_, storage.addr, storage.addr_len))
477 return MapSystemError(errno); 473 return MapSystemError(errno);
478 } 474 }
479 } 475 }
480 476
481 DCHECK(!core_); 477 DCHECK(!core_);
482 core_ = new Core(this); 478 core_ = new Core(this);
483 // WSAEventSelect sets the socket to non-blocking mode as a side effect. 479 // WSAEventSelect sets the socket to non-blocking mode as a side effect.
484 // Our connect() and recv() calls require that the socket be non-blocking. 480 // Our connect() and recv() calls require that the socket be non-blocking.
485 WSAEventSelect(socket_, core_->read_overlapped_.hEvent, FD_CONNECT); 481 WSAEventSelect(socket_, core_->read_overlapped_.hEvent, FD_CONNECT);
486 482
483 SockaddrStorage storage;
484 if (!endpoint.ToSockAddr(storage.addr, &storage.addr_len))
485 return ERR_INVALID_ARGUMENT;
eroman 2012/05/04 01:08:41 I wander if these failure are possible? When build
szym 2012/05/04 02:38:29 Agreed that ToSockAddr should ideally not return f
487 connect_start_time_ = base::TimeTicks::Now(); 486 connect_start_time_ = base::TimeTicks::Now();
488 if (!connect(socket_, ai->ai_addr, static_cast<int>(ai->ai_addrlen))) { 487 if (!connect(socket_, storage.addr, storage.addr_len)) {
489 // Connected without waiting! 488 // Connected without waiting!
490 // 489 //
491 // The MSDN page for connect says: 490 // The MSDN page for connect says:
492 // With a nonblocking socket, the connection attempt cannot be completed 491 // With a nonblocking socket, the connection attempt cannot be completed
493 // immediately. In this case, connect will return SOCKET_ERROR, and 492 // immediately. In this case, connect will return SOCKET_ERROR, and
494 // WSAGetLastError will return WSAEWOULDBLOCK. 493 // WSAGetLastError will return WSAEWOULDBLOCK.
495 // which implies that for a nonblocking socket, connect never returns 0. 494 // which implies that for a nonblocking socket, connect never returns 0.
496 // It's not documented whether the event object will be signaled or not 495 // It's not documented whether the event object will be signaled or not
497 // if connect does return 0. So the code below is essentially dead code 496 // if connect does return 0. So the code below is essentially dead code
498 // and we don't know if it's correct. 497 // and we don't know if it's correct.
(...skipping 26 matching lines...) Expand all
525 if (result == OK) { 524 if (result == OK) {
526 connect_time_micros_ = base::TimeTicks::Now() - connect_start_time_; 525 connect_time_micros_ = base::TimeTicks::Now() - connect_start_time_;
527 use_history_.set_was_ever_connected(); 526 use_history_.set_was_ever_connected();
528 return OK; // Done! 527 return OK; // Done!
529 } 528 }
530 529
531 // Close whatever partially connected socket we currently have. 530 // Close whatever partially connected socket we currently have.
532 DoDisconnect(); 531 DoDisconnect();
533 532
534 // Try to fall back to the next address in the list. 533 // Try to fall back to the next address in the list.
535 if (current_ai_->ai_next) { 534 if (current_address_index_ + 1 < addresses_.size()) {
536 next_connect_state_ = CONNECT_STATE_CONNECT; 535 next_connect_state_ = CONNECT_STATE_CONNECT;
537 current_ai_ = current_ai_->ai_next; 536 ++current_address_index_;
538 return OK; 537 return OK;
539 } 538 }
540 539
541 // Otherwise there is nothing to fall back to, so give up. 540 // Otherwise there is nothing to fall back to, so give up.
542 return result; 541 return result;
543 } 542 }
544 543
545 void TCPClientSocketWin::Disconnect() { 544 void TCPClientSocketWin::Disconnect() {
546 DoDisconnect(); 545 DoDisconnect();
547 current_ai_ = NULL; 546 current_address_index_ = addresses_.size();
eroman 2012/05/04 01:08:41 Same comment as earlier, I wander if this is actua
szym 2012/05/04 02:38:29 Agreed. Will fix.
eroman 2012/05/04 19:37:36 Sorry, I suggest leaving this in place, as a reset
548 } 547 }
549 548
550 void TCPClientSocketWin::DoDisconnect() { 549 void TCPClientSocketWin::DoDisconnect() {
551 DCHECK(CalledOnValidThread()); 550 DCHECK(CalledOnValidThread());
552 551
553 if (socket_ == INVALID_SOCKET) 552 if (socket_ == INVALID_SOCKET)
554 return; 553 return;
555 554
556 // Note: don't use CancelIo to cancel pending IO because it doesn't work 555 // Note: don't use CancelIo to cancel pending IO because it doesn't work
557 // when there is a Winsock layered service provider. 556 // when there is a Winsock layered service provider.
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
622 return false; 621 return false;
623 622
624 return true; 623 return true;
625 } 624 }
626 625
627 int TCPClientSocketWin::GetPeerAddress(AddressList* address) const { 626 int TCPClientSocketWin::GetPeerAddress(AddressList* address) const {
628 DCHECK(CalledOnValidThread()); 627 DCHECK(CalledOnValidThread());
629 DCHECK(address); 628 DCHECK(address);
630 if (!IsConnected()) 629 if (!IsConnected())
631 return ERR_SOCKET_NOT_CONNECTED; 630 return ERR_SOCKET_NOT_CONNECTED;
632 *address = AddressList::CreateByCopyingFirstAddress(current_ai_); 631 *address = AddressList(addresses_[current_address_index_]);
633 return OK; 632 return OK;
634 } 633 }
635 634
636 int TCPClientSocketWin::GetLocalAddress(IPEndPoint* address) const { 635 int TCPClientSocketWin::GetLocalAddress(IPEndPoint* address) const {
637 DCHECK(CalledOnValidThread()); 636 DCHECK(CalledOnValidThread());
638 DCHECK(address); 637 DCHECK(address);
639 if (!IsConnected()) 638 if (!IsConnected())
640 return ERR_SOCKET_NOT_CONNECTED; 639 return ERR_SOCKET_NOT_CONNECTED;
641 640
642 struct sockaddr_storage addr_storage; 641 struct sockaddr_storage addr_storage;
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after
908 use_history_.set_was_used_to_convey_data(); 907 use_history_.set_was_used_to_convey_data();
909 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, num_bytes, 908 net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, num_bytes,
910 core_->write_buffer_.buf); 909 core_->write_buffer_.buf);
911 } 910 }
912 } 911 }
913 core_->write_iobuffer_ = NULL; 912 core_->write_iobuffer_ = NULL;
914 DoWriteCallback(rv); 913 DoWriteCallback(rv);
915 } 914 }
916 915
917 } // namespace net 916 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698