// Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/base/address_list.h" #include #include #include #include #include "base/containers/flat_map.h" #include "base/logging.h" #include "base/values.h" #include "net/base/sys_addrinfo.h" namespace net { AddressList::AddressList() = default; AddressList::AddressList(const AddressList&) = default; AddressList& AddressList::operator=(const AddressList&) = default; AddressList::AddressList(AddressList&&) = default; AddressList& AddressList::operator=(AddressList&&) = default; AddressList::~AddressList() = default; AddressList::AddressList(const IPEndPoint& endpoint) { push_back(endpoint); } AddressList::AddressList(const IPEndPoint& endpoint, std::vector aliases) : dns_aliases_(std::move(aliases)) { push_back(endpoint); } AddressList::AddressList(std::vector endpoints) : endpoints_(std::move(endpoints)) {} // static AddressList AddressList::CreateFromIPAddress(const IPAddress& address, uint16_t port) { return AddressList(IPEndPoint(address, port)); } // static AddressList AddressList::CreateFromIPAddressList( const IPAddressList& addresses, std::vector aliases) { AddressList list; for (const auto& address : addresses) { list.push_back(IPEndPoint(address, 0)); } list.SetDnsAliases(std::move(aliases)); return list; } // static AddressList AddressList::CreateFromAddrinfo(const struct addrinfo* head) { DCHECK(head); AddressList list; if (head->ai_canonname) { std::vector aliases({std::string(head->ai_canonname)}); list.SetDnsAliases(std::move(aliases)); } for (const struct addrinfo* ai = head; ai; ai = ai->ai_next) { IPEndPoint ipe; // NOTE: Ignoring non-INET* families. if (ipe.FromSockAddr(ai->ai_addr, static_cast(ai->ai_addrlen))) list.push_back(ipe); else DLOG(WARNING) << "Unknown family found in addrinfo: " << ai->ai_family; } return list; } // static AddressList AddressList::CopyWithPort(const AddressList& list, uint16_t port) { AddressList out; out.SetDnsAliases(list.dns_aliases()); for (const auto& i : list) out.push_back(IPEndPoint(i.address(), port)); return out; } void AddressList::SetDefaultCanonicalName() { DCHECK(!empty()); DCHECK(dns_aliases_.empty()); SetDnsAliases({front().ToStringWithoutPort()}); } void AddressList::SetDnsAliases(std::vector aliases) { // TODO(cammie): Track down the callers who use {""} for `aliases` and // update so that we can enforce by DCHECK below. // The empty canonical name is represented by a empty `dns_aliases_` // vector, so in this case we reset the field. if (aliases == std::vector({""})) { dns_aliases_ = std::vector(); return; } dns_aliases_ = std::move(aliases); } void AddressList::AppendDnsAliases(std::vector aliases) { DCHECK(aliases != std::vector({""})); using iter_t = std::vector::iterator; dns_aliases_.insert(dns_aliases_.end(), std::move_iterator(aliases.begin()), std::move_iterator(aliases.end())); } base::Value AddressList::NetLogParams() const { base::Value::Dict dict; base::Value::List address_list; for (const auto& ip_endpoint : *this) address_list.Append(ip_endpoint.ToString()); dict.Set("address_list", std::move(address_list)); base::Value::List alias_list; for (const std::string& alias : dns_aliases_) alias_list.Append(alias); dict.Set("aliases", std::move(alias_list)); return base::Value(std::move(dict)); } void AddressList::Deduplicate() { if (size() > 1) { std::vector> make_me_into_a_map(size()); for (auto& addr : *this) make_me_into_a_map.emplace_back(addr, 0); base::flat_map inserted(std::move(make_me_into_a_map)); std::vector deduplicated_addresses; deduplicated_addresses.reserve(inserted.size()); for (const auto& addr : *this) { int& count = inserted[addr]; if (!count) { deduplicated_addresses.push_back(addr); ++count; } } endpoints_.swap(deduplicated_addresses); } } } // namespace net