15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/address_sorter.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <winsock2.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/worker_pool.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/address_list.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/ip_endpoint.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/winsock_init.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class AddressSorterWin : public AddressSorter {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddressSorterWin() {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EnsureWinsockInit();
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~AddressSorterWin() {}
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // AddressSorter:
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Sort(const AddressList& list,
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const CallbackType& callback) const OVERRIDE {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!list.empty());
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<Job> job = new Job(list, callback);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Executes the SIO_ADDRESS_LIST_SORT ioctl on the WorkerPool, and
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // performs the necessary conversions to/from AddressList.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class Job : public base::RefCountedThreadSafe<Job> {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   public:
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Job(const AddressList& list, const CallbackType& callback)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        : callback_(callback),
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          buffer_size_(sizeof(SOCKET_ADDRESS_LIST) +
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       list.size() * (sizeof(SOCKET_ADDRESS) +
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      sizeof(SOCKADDR_STORAGE))),
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          input_buffer_(reinterpret_cast<SOCKET_ADDRESS_LIST*>(
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              malloc(buffer_size_))),
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          output_buffer_(reinterpret_cast<SOCKET_ADDRESS_LIST*>(
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              malloc(buffer_size_))),
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          success_(false) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      input_buffer_->iAddressCount = list.size();
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SOCKADDR_STORAGE* storage = reinterpret_cast<SOCKADDR_STORAGE*>(
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          input_buffer_->Address + input_buffer_->iAddressCount);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t i = 0; i < list.size(); ++i) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IPEndPoint ipe = list[i];
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Addresses must be sockaddr_in6.
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (ipe.GetFamily() == ADDRESS_FAMILY_IPV4) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ipe = IPEndPoint(ConvertIPv4NumberToIPv6Number(ipe.address()),
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           ipe.port());
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(storage + i);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        socklen_t addr_len = sizeof(SOCKADDR_STORAGE);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bool result = ipe.ToSockAddr(addr, &addr_len);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK(result);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        input_buffer_->Address[i].lpSockaddr = addr;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        input_buffer_->Address[i].iSockaddrLength = addr_len;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!base::WorkerPool::PostTaskAndReply(
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&Job::Run, this),
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&Job::OnComplete, this),
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          false /* task is slow */)) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "WorkerPool::PostTaskAndReply failed";
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OnComplete();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   private:
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    friend class base::RefCountedThreadSafe<Job>;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ~Job() {}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Executed on the WorkerPool.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void Run() {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SOCKET sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (sock == INVALID_SOCKET)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DWORD result_size = 0;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int result = WSAIoctl(sock, SIO_ADDRESS_LIST_SORT, input_buffer_.get(),
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            buffer_size_, output_buffer_.get(), buffer_size_,
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            &result_size, NULL, NULL);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (result == SOCKET_ERROR) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "SIO_ADDRESS_LIST_SORT failed " << WSAGetLastError();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        success_ = true;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      closesocket(sock);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Executed on the calling thread.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void OnComplete() {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AddressList list;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (success_) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        list.reserve(output_buffer_->iAddressCount);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (int i = 0; i < output_buffer_->iAddressCount; ++i) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          IPEndPoint ipe;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ipe.FromSockAddr(output_buffer_->Address[i].lpSockaddr,
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           output_buffer_->Address[i].iSockaddrLength);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Unmap V4MAPPED IPv6 addresses so that Happy Eyeballs works.
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (IsIPv4Mapped(ipe.address())) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ipe = IPEndPoint(ConvertIPv4MappedToIPv4(ipe.address()),
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     ipe.port());
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          list.push_back(ipe);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      callback_.Run(success_, list);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const CallbackType callback_;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const size_t buffer_size_;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr_malloc<SOCKET_ADDRESS_LIST> input_buffer_;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr_malloc<SOCKET_ADDRESS_LIST> output_buffer_;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool success_;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DISALLOW_COPY_AND_ASSIGN(Job);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(AddressSorterWin);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Merges |list_ipv4| and |list_ipv6| before passing it to |callback|, but
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// only if |success| is true.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MergeResults(const AddressSorter::CallbackType& callback,
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  const AddressList& list_ipv4,
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  bool success,
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  const AddressList& list_ipv6) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!success) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback.Run(false, AddressList());
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddressList list;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  list.insert(list.end(), list_ipv6.begin(), list_ipv6.end());
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  list.insert(list.end(), list_ipv4.begin(), list_ipv4.end());
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback.Run(true, list);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Wrapper for AddressSorterWin which does not sort IPv4 or IPv4-mapped
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// addresses but always puts them at the end of the list. Needed because the
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SIO_ADDRESS_LIST_SORT does not support IPv4 addresses on Windows XP.
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class AddressSorterWinXP : public AddressSorter {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddressSorterWinXP() {}
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~AddressSorterWinXP() {}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // AddressSorter:
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Sort(const AddressList& list,
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const CallbackType& callback) const OVERRIDE {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddressList list_ipv4;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddressList list_ipv6;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < list.size(); ++i) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const IPEndPoint& ipe = list[i];
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (ipe.GetFamily() == ADDRESS_FAMILY_IPV4) {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        list_ipv4.push_back(ipe);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        list_ipv6.push_back(ipe);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!list_ipv6.empty()) {
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorter_.Sort(list_ipv6, base::Bind(&MergeResults, callback, list_ipv4));
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Should not be called with IPv4-only addresses.";
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      callback.Run(true, list);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddressSorterWin sorter_;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(AddressSorterWinXP);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<AddressSorter> AddressSorter::CreateAddressSorter() {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::win::GetVersion() < base::win::VERSION_VISTA)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return scoped_ptr<AddressSorter>(new AddressSorterWinXP());
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return scoped_ptr<AddressSorter>(new AddressSorterWin());
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
199