OLD | NEW |
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/udp/udp_socket_win.h" | 5 #include "net/udp/udp_socket_win.h" |
6 | 6 |
7 #include <mstcpip.h> | 7 #include <mstcpip.h> |
8 | 8 |
9 #include "base/callback.h" | 9 #include "base/callback.h" |
10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
(...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
477 addr_family_ = addr_family; | 477 addr_family_ = addr_family; |
478 socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, IPPROTO_UDP); | 478 socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, IPPROTO_UDP); |
479 if (socket_ == INVALID_SOCKET) | 479 if (socket_ == INVALID_SOCKET) |
480 return MapSystemError(WSAGetLastError()); | 480 return MapSystemError(WSAGetLastError()); |
481 core_ = new Core(this); | 481 core_ = new Core(this); |
482 return OK; | 482 return OK; |
483 } | 483 } |
484 | 484 |
485 int UDPSocketWin::SetReceiveBufferSize(int32 size) { | 485 int UDPSocketWin::SetReceiveBufferSize(int32 size) { |
486 DCHECK(CalledOnValidThread()); | 486 DCHECK(CalledOnValidThread()); |
487 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, | 487 if (is_connected()) { |
488 reinterpret_cast<const char*>(&size), sizeof(size)); | 488 int result = SetReceiveBufferSizeInternal(size); |
489 if (rv != 0) | 489 if (result != OK) |
490 return MapSystemError(WSAGetLastError()); | 490 return result; |
491 | 491 } |
492 // According to documentation, setsockopt may succeed, but we need to check | 492 socket_options_ |= SOCKET_OPTION_RCVBUF_SIZE; |
493 // the results via getsockopt to be sure it works on Windows. | 493 rcvbuf_size_ = size; |
494 int32 actual_size = 0; | 494 return OK; |
495 int option_size = sizeof(actual_size); | |
496 rv = getsockopt(socket_, SOL_SOCKET, SO_RCVBUF, | |
497 reinterpret_cast<char*>(&actual_size), &option_size); | |
498 if (rv != 0) | |
499 return MapSystemError(WSAGetLastError()); | |
500 if (actual_size >= size) | |
501 return OK; | |
502 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SocketUnchangeableReceiveBuffer", | |
503 actual_size, 1000, 1000000, 50); | |
504 return ERR_SOCKET_RECEIVE_BUFFER_SIZE_UNCHANGEABLE; | |
505 } | 495 } |
506 | 496 |
507 int UDPSocketWin::SetSendBufferSize(int32 size) { | 497 int UDPSocketWin::SetSendBufferSize(int32 size) { |
508 DCHECK(CalledOnValidThread()); | 498 DCHECK(CalledOnValidThread()); |
509 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, | 499 if (is_connected()) { |
510 reinterpret_cast<const char*>(&size), sizeof(size)); | 500 int result = SetReceiveBufferSizeInternal(size); |
511 if (rv != 0) | 501 if (result != OK) |
512 return MapSystemError(WSAGetLastError()); | 502 return result; |
513 // According to documentation, setsockopt may succeed, but we need to check | 503 } |
514 // the results via getsockopt to be sure it works on Windows. | 504 socket_options_ |= SOCKET_OPTION_SNDBUF_SIZE; |
515 int32 actual_size = 0; | 505 sndbuf_size_ = size; |
516 int option_size = sizeof(actual_size); | 506 return OK; |
517 rv = getsockopt(socket_, SOL_SOCKET, SO_SNDBUF, | |
518 reinterpret_cast<char*>(&actual_size), &option_size); | |
519 if (rv != 0) | |
520 return MapSystemError(WSAGetLastError()); | |
521 if (actual_size >= size) | |
522 return OK; | |
523 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SocketUnchangeableSendBuffer", | |
524 actual_size, 1000, 1000000, 50); | |
525 return ERR_SOCKET_SEND_BUFFER_SIZE_UNCHANGEABLE; | |
526 } | 507 } |
527 | 508 |
528 void UDPSocketWin::AllowAddressReuse() { | 509 int UDPSocketWin::AllowAddressReuse() { |
529 DCHECK(CalledOnValidThread()); | 510 DCHECK(CalledOnValidThread()); |
530 DCHECK(!is_connected()); | 511 if (is_connected()) { |
531 | 512 int result = SetAddressReuseInternal(true); |
| 513 if (result != OK) |
| 514 return result; |
| 515 } |
532 socket_options_ |= SOCKET_OPTION_REUSE_ADDRESS; | 516 socket_options_ |= SOCKET_OPTION_REUSE_ADDRESS; |
| 517 return OK; |
533 } | 518 } |
534 | 519 |
535 void UDPSocketWin::AllowBroadcast() { | 520 int UDPSocketWin::DisallowAddressReuse() { |
536 DCHECK(CalledOnValidThread()); | 521 DCHECK(CalledOnValidThread()); |
537 DCHECK(!is_connected()); | 522 if (is_connected()) { |
| 523 int result = SetAddressReuseInternal(false); |
| 524 if (result != OK) |
| 525 return result; |
| 526 } |
| 527 socket_options_ &= ~SOCKET_OPTION_REUSE_ADDRESS; |
| 528 return OK; |
| 529 } |
538 | 530 |
| 531 int UDPSocketWin::AllowBroadcast() { |
| 532 DCHECK(CalledOnValidThread()); |
| 533 if (is_connected()) { |
| 534 int result = SetBroadcastInternal(true); |
| 535 if (result != OK) |
| 536 return result; |
| 537 } |
539 socket_options_ |= SOCKET_OPTION_BROADCAST; | 538 socket_options_ |= SOCKET_OPTION_BROADCAST; |
| 539 return OK; |
| 540 } |
| 541 |
| 542 int UDPSocketWin::DisallowBroadcast() { |
| 543 DCHECK(CalledOnValidThread()); |
| 544 if (is_connected()) { |
| 545 int result = SetBroadcastInternal(false); |
| 546 if (result != OK) |
| 547 return result; |
| 548 } |
| 549 socket_options_ &= ~SOCKET_OPTION_BROADCAST; |
| 550 return OK; |
540 } | 551 } |
541 | 552 |
542 void UDPSocketWin::DoReadCallback(int rv) { | 553 void UDPSocketWin::DoReadCallback(int rv) { |
543 DCHECK_NE(rv, ERR_IO_PENDING); | 554 DCHECK_NE(rv, ERR_IO_PENDING); |
544 DCHECK(!read_callback_.is_null()); | 555 DCHECK(!read_callback_.is_null()); |
545 | 556 |
546 // since Run may result in Read being called, clear read_callback_ up front. | 557 // since Run may result in Read being called, clear read_callback_ up front. |
547 CompletionCallback c = read_callback_; | 558 CompletionCallback c = read_callback_; |
548 read_callback_.Reset(); | 559 read_callback_.Reset(); |
549 c.Run(rv); | 560 c.Run(rv); |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
708 return result; | 719 return result; |
709 } | 720 } |
710 } | 721 } |
711 | 722 |
712 core_->WatchForWrite(); | 723 core_->WatchForWrite(); |
713 core_->write_iobuffer_ = buf; | 724 core_->write_iobuffer_ = buf; |
714 return ERR_IO_PENDING; | 725 return ERR_IO_PENDING; |
715 } | 726 } |
716 | 727 |
717 int UDPSocketWin::SetSocketOptions() { | 728 int UDPSocketWin::SetSocketOptions() { |
718 BOOL true_value = 1; | 729 DCHECK(CalledOnValidThread()); |
| 730 DCHECK(is_connected()); |
| 731 |
719 if (socket_options_ & SOCKET_OPTION_REUSE_ADDRESS) { | 732 if (socket_options_ & SOCKET_OPTION_REUSE_ADDRESS) { |
720 int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, | 733 int rv = SetAddressReuseInternal(true); |
721 reinterpret_cast<const char*>(&true_value), | 734 if (rv != OK) |
722 sizeof(true_value)); | 735 return rv; |
723 if (rv < 0) | |
724 return MapSystemError(WSAGetLastError()); | |
725 } | 736 } |
726 if (socket_options_ & SOCKET_OPTION_BROADCAST) { | 737 if (socket_options_ & SOCKET_OPTION_BROADCAST) { |
727 int rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, | 738 int rv = SetBroadcastInternal(true); |
728 reinterpret_cast<const char*>(&true_value), | 739 if (rv != OK) |
729 sizeof(true_value)); | 740 return rv; |
730 if (rv < 0) | |
731 return MapSystemError(WSAGetLastError()); | |
732 } | 741 } |
733 if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) { | 742 if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) { |
734 DWORD loop = 0; | 743 DWORD loop = 0; |
735 int protocol_level = | 744 int protocol_level = |
736 addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; | 745 addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; |
737 int option = | 746 int option = |
738 addr_family_ == AF_INET ? IP_MULTICAST_LOOP: IPV6_MULTICAST_LOOP; | 747 addr_family_ == AF_INET ? IP_MULTICAST_LOOP: IPV6_MULTICAST_LOOP; |
739 int rv = setsockopt(socket_, protocol_level, option, | 748 int rv = setsockopt(socket_, protocol_level, option, |
740 reinterpret_cast<const char*>(&loop), sizeof(loop)); | 749 reinterpret_cast<const char*>(&loop), sizeof(loop)); |
741 if (rv < 0) | 750 if (rv < 0) |
742 return MapSystemError(WSAGetLastError()); | 751 return MapSystemError(WSAGetLastError()); |
743 } | 752 } |
| 753 if (socket_options_ & SOCKET_OPTION_RCVBUF_SIZE) { |
| 754 int rv = SetReceiveBufferSizeInternal(rcvbuf_size_); |
| 755 if (rv != OK) |
| 756 return rv; |
| 757 } |
| 758 if (socket_options_ & SOCKET_OPTION_SNDBUF_SIZE) { |
| 759 int rv = SetSendBufferSizeInternal(sndbuf_size_); |
| 760 if (rv != OK) |
| 761 return rv; |
| 762 } |
744 if (multicast_time_to_live_ != 1) { | 763 if (multicast_time_to_live_ != 1) { |
745 DWORD hops = multicast_time_to_live_; | 764 DWORD hops = multicast_time_to_live_; |
746 int protocol_level = | 765 int protocol_level = |
747 addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; | 766 addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; |
748 int option = | 767 int option = |
749 addr_family_ == AF_INET ? IP_MULTICAST_TTL: IPV6_MULTICAST_HOPS; | 768 addr_family_ == AF_INET ? IP_MULTICAST_TTL: IPV6_MULTICAST_HOPS; |
750 int rv = setsockopt(socket_, protocol_level, option, | 769 int rv = setsockopt(socket_, protocol_level, option, |
751 reinterpret_cast<const char*>(&hops), sizeof(hops)); | 770 reinterpret_cast<const char*>(&hops), sizeof(hops)); |
752 if (rv < 0) | 771 if (rv < 0) |
753 return MapSystemError(WSAGetLastError()); | 772 return MapSystemError(WSAGetLastError()); |
(...skipping 20 matching lines...) Expand all Loading... |
774 break; | 793 break; |
775 } | 794 } |
776 default: | 795 default: |
777 NOTREACHED() << "Invalid address family"; | 796 NOTREACHED() << "Invalid address family"; |
778 return ERR_ADDRESS_INVALID; | 797 return ERR_ADDRESS_INVALID; |
779 } | 798 } |
780 } | 799 } |
781 return OK; | 800 return OK; |
782 } | 801 } |
783 | 802 |
| 803 int UDPSocketWin::SetAddressReuseInternal(bool address_reuse) { |
| 804 DCHECK(CalledOnValidThread()); |
| 805 DCHECK(is_connected()); |
| 806 |
| 807 int opt_value = address_reuse ? 1 : 0; |
| 808 int rv = setsockopt( |
| 809 socket_, SOL_SOCKET, SO_REUSEADDR, |
| 810 reinterpret_cast<const char*>(&opt_value), sizeof(opt_value)); |
| 811 return rv == 0 ? OK : MapSystemError(WSAGetLastError()); |
| 812 } |
| 813 |
| 814 int UDPSocketWin::SetBroadcastInternal(bool broadcast) { |
| 815 DCHECK(CalledOnValidThread()); |
| 816 DCHECK(is_connected()); |
| 817 |
| 818 int opt_value = broadcast ? 1 : 0; |
| 819 int rv = setsockopt( |
| 820 socket_, SOL_SOCKET, SO_BROADCAST, |
| 821 reinterpret_cast<const char*>(&opt_value), sizeof(opt_value)); |
| 822 return rv == 0 ? OK : MapSystemError(WSAGetLastError()); |
| 823 } |
| 824 |
| 825 int UDPSocketWin::SetReceiveBufferSizeInternal(int32 size) { |
| 826 DCHECK(CalledOnValidThread()); |
| 827 DCHECK(is_connected()); |
| 828 |
| 829 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, |
| 830 reinterpret_cast<const char*>(&size), sizeof(size)); |
| 831 if (rv != 0) |
| 832 return MapSystemError(WSAGetLastError()); |
| 833 |
| 834 // According to documentation, setsockopt may succeed, but we need to check |
| 835 // the results via getsockopt to be sure it works on Windows. |
| 836 int32 actual_size = 0; |
| 837 int option_size = sizeof(actual_size); |
| 838 rv = getsockopt(socket_, SOL_SOCKET, SO_RCVBUF, |
| 839 reinterpret_cast<char*>(&actual_size), &option_size); |
| 840 if (rv != 0) |
| 841 return MapSystemError(WSAGetLastError()); |
| 842 if (actual_size >= size) |
| 843 return OK; |
| 844 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SocketUnchangeableReceiveBuffer", |
| 845 actual_size, 1000, 1000000, 50); |
| 846 return ERR_SOCKET_RECEIVE_BUFFER_SIZE_UNCHANGEABLE; |
| 847 } |
| 848 |
| 849 int UDPSocketWin::SetSendBufferSizeInternal(int32 size) { |
| 850 DCHECK(CalledOnValidThread()); |
| 851 DCHECK(is_connected()); |
| 852 |
| 853 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, |
| 854 reinterpret_cast<const char*>(&size), sizeof(size)); |
| 855 if (rv != 0) |
| 856 return MapSystemError(WSAGetLastError()); |
| 857 // According to documentation, setsockopt may succeed, but we need to check |
| 858 // the results via getsockopt to be sure it works on Windows. |
| 859 int32 actual_size = 0; |
| 860 int option_size = sizeof(actual_size); |
| 861 rv = getsockopt(socket_, SOL_SOCKET, SO_SNDBUF, |
| 862 reinterpret_cast<char*>(&actual_size), &option_size); |
| 863 if (rv != 0) |
| 864 return MapSystemError(WSAGetLastError()); |
| 865 if (actual_size >= size) |
| 866 return OK; |
| 867 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SocketUnchangeableSendBuffer", |
| 868 actual_size, 1000, 1000000, 50); |
| 869 return ERR_SOCKET_SEND_BUFFER_SIZE_UNCHANGEABLE; |
| 870 } |
| 871 |
784 int UDPSocketWin::DoBind(const IPEndPoint& address) { | 872 int UDPSocketWin::DoBind(const IPEndPoint& address) { |
785 SockaddrStorage storage; | 873 SockaddrStorage storage; |
786 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) | 874 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) |
787 return ERR_ADDRESS_INVALID; | 875 return ERR_ADDRESS_INVALID; |
788 int rv = bind(socket_, storage.addr, storage.addr_len); | 876 int rv = bind(socket_, storage.addr, storage.addr_len); |
789 if (rv == 0) | 877 if (rv == 0) |
790 return OK; | 878 return OK; |
791 int last_error = WSAGetLastError(); | 879 int last_error = WSAGetLastError(); |
792 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketBindErrorFromWinOS", last_error); | 880 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketBindErrorFromWinOS", last_error); |
793 // Map some codes that are special to bind() separately. | 881 // Map some codes that are special to bind() separately. |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1016 NULL); | 1104 NULL); |
1017 | 1105 |
1018 return OK; | 1106 return OK; |
1019 } | 1107 } |
1020 | 1108 |
1021 void UDPSocketWin::DetachFromThread() { | 1109 void UDPSocketWin::DetachFromThread() { |
1022 base::NonThreadSafe::DetachFromThread(); | 1110 base::NonThreadSafe::DetachFromThread(); |
1023 } | 1111 } |
1024 | 1112 |
1025 } // namespace net | 1113 } // namespace net |
OLD | NEW |