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

Unified Diff: net/dns/address_sorter_win.cc

Issue 10442098: [net/dns] Resolve AF_UNSPEC on dual-stacked systems. Sort addresses according to RFC3484. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Minor edits. Fix one typo in variable name. Created 8 years, 5 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 side-by-side diff with in-line comments
Download patch
Index: net/dns/address_sorter_win.cc
diff --git a/net/dns/address_sorter_win.cc b/net/dns/address_sorter_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..062b635a309d144c6ad8c54c7f929e25e491fac8
--- /dev/null
+++ b/net/dns/address_sorter_win.cc
@@ -0,0 +1,144 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/dns/address_sorter.h"
+
+#include <winsock2.h>
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/win/windows_version.h"
+#include "net/base/address_list.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/winsock_init.h"
+
+namespace net {
+
+namespace {
+
+// If |ipe| has IPv4-mapped IPv6 address, converts it to IPv4.
mmenke 2012/07/30 15:37:00 nit: "and leaves all other addresses unmodified."
+void ConvertIPv4MappedToIPv4(IPEndPoint* ipe) {
mmenke 2012/07/30 15:37:00 May want to put this in net_util.cc. I don't see
+ DCHECK_EQ(AF_INET6, ipe->GetFamily());
+ const IPAddressNumber& address = ipe->address();
+ const unsigned char prefix[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
+ if (std::equal(address.begin(), address.begin() + arraysize(prefix),
+ prefix)) {
+ *ipe = IPEndPoint(
+ IPAddressNumber(address.begin() + arraysize(prefix), address.end()),
+ ipe->port());
+ }
+}
+
+class AddressSorterWin : public AddressSorter {
+ public:
+ AddressSorterWin() : socket_(INVALID_SOCKET) {
+ EnsureWinsockInit();
+ socket_ = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ DCHECK_NE(INVALID_SOCKET, socket_);
+ }
+
+ virtual ~AddressSorterWin() {
+ closesocket(socket_);
+ }
+
+ virtual bool Sort(AddressList* list) const OVERRIDE {
+ size_t heap_size = sizeof(SOCKET_ADDRESS_LIST) +
+ list->size() * (sizeof(SOCKET_ADDRESS) + sizeof(SOCKADDR_STORAGE));
+ scoped_ptr_malloc<SOCKET_ADDRESS_LIST> heap_in(
+ reinterpret_cast<SOCKET_ADDRESS_LIST*>(malloc(heap_size)));
+
+ SOCKET_ADDRESS_LIST* sort_list = heap_in.get();
+ sort_list->iAddressCount = list->size();
+ SOCKADDR_STORAGE* storage = reinterpret_cast<SOCKADDR_STORAGE*>(
+ sort_list->Address + sort_list->iAddressCount);
+
+ for (size_t i = 0; i < list->size(); ++i) {
+ IPEndPoint& ipe = (*list)[i];
+ // Addresses must be sockaddr_in6.
+ if (ipe.GetFamily() == AF_INET) {
+ ipe = IPEndPoint(ConvertIPv4NumberToIPv6Number(ipe.address()),
+ ipe.port());
+ }
+
+ struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(storage + i);
+ socklen_t addr_len = sizeof(SOCKADDR_STORAGE);
+ bool result = ipe.ToSockAddr(addr, &addr_len);
+ DCHECK(result);
+ sort_list->Address[i].lpSockaddr = addr;
+ sort_list->Address[i].iSockaddrLength = addr_len;
+ }
+
+ DWORD result_size = 0;
+ int result = WSAIoctl(socket_, SIO_ADDRESS_LIST_SORT, sort_list, heap_size,
cbentzel 2012/07/30 15:53:43 Could this be blocking the IO thread?
szym 2012/07/30 16:28:45 Yes, but no more than GetAdaptersAddresses. The wo
mmenke1 2012/07/30 17:19:06 If I recall correctly, eroman has said previously
+ sort_list, heap_size, &result_size, NULL, NULL);
mmenke 2012/07/30 15:37:00 Wonder if this ever eats addresses depending on lo
szym 2012/07/30 16:28:45 I'll need to test it, but either way I wouldn't te
+ if (result == SOCKET_ERROR) {
+ LOG(ERROR) << "SIO_ADDRESS_LIST_SORT failed" << WSAGetLastError();
+ return false; // Unsorted.
+ }
+ list->clear();
+ for (int i = 0; i < sort_list->iAddressCount; ++i) {
+ IPEndPoint ipe;
+ ipe.FromSockAddr(sort_list->Address[i].lpSockaddr,
+ sort_list->Address[i].iSockaddrLength);
+ // Unmap V4MAPPED IPv6 addresses so that Happy Eyeballs works properly.
+ ConvertIPv4MappedToIPv4(&ipe);
+ list->push_back(ipe);
+ }
+ return true;
+ }
+
+ private:
+ // The socket to run WSAIoctl on.
+ SOCKET socket_;
+
+ DISALLOW_COPY_AND_ASSIGN(AddressSorterWin);
+};
+
+// Wrapper for AddressSorterWin which does not sort IPv4 or IPv4-mapped
+// addresses but always puts them at the end of the list. Needed because the
+// SIO_ADDRESS_LIST_SORT does not support IPv4 addresses on Windows XP.
+class AddressSorterWinXP : public AddressSorter {
+ public:
+ AddressSorterWinXP() {}
+ virtual ~AddressSorterWinXP() {}
+
+ virtual bool Sort(AddressList* list) const OVERRIDE {
+ AddressList list_ipv4;
+ AddressList list_ipv6;
+ for (size_t i = 0; i < list->size(); ++i) {
+ IPEndPoint ipe = (*list)[i];
+ if (ipe.GetFamily() == AF_INET6)
+ ConvertIPv4MappedToIPv4(&ipe);
+ if (ipe.GetFamily() == AF_INET) {
+ list_ipv4.push_back(ipe);
+ } else {
+ list_ipv6.push_back(ipe);
+ }
+ }
+ if (!list_ipv6.empty() && !sorter_.Sort(&list_ipv6))
+ return false;
+ list->clear();
+ list->insert(list->end(), list_ipv6.begin(), list_ipv6.end());
+ list->insert(list->end(), list_ipv4.begin(), list_ipv4.end());
+ return true;
+ }
+
+ private:
+ AddressSorterWin sorter_;
+
+ DISALLOW_COPY_AND_ASSIGN(AddressSorterWinXP);
+};
+
+} // namespace
+
+// static
+scoped_ptr<AddressSorter> AddressSorter::CreateAddressSorter() {
+ if (base::win::GetVersion() < base::win::VERSION_VISTA)
+ return scoped_ptr<AddressSorter>(new AddressSorterWinXP());
+ return scoped_ptr<AddressSorter>(new AddressSorterWin());
+}
+
+} // namespace net
+

Powered by Google App Engine
This is Rietveld 408576698