blob: 541a90354db25c3fbe18e8387e22470c1f25b0bb [file] [log] [blame]
// 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/base/address_list.h"
#include <iterator>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/values.h"
#include "net/base/sys_addrinfo.h"
#include "net/log/net_log_capture_mode.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<std::string> aliases)
: dns_aliases_(std::move(aliases)) {
push_back(endpoint);
}
// static
AddressList AddressList::CreateFromIPAddress(const IPAddress& address,
uint16_t port) {
return AddressList(IPEndPoint(address, port));
}
// static
AddressList AddressList::CreateFromIPAddressList(
const IPAddressList& addresses,
std::vector<std::string> aliases) {
AddressList list;
for (auto iter = addresses.begin(); iter != addresses.end(); ++iter) {
list.push_back(IPEndPoint(*iter, 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<std::string> 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<socklen_t>(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;
}
// TODO(cammie/ericorth): Consider changing the return value to
// base::StringPiece (by non-const value), which is often a better type
// for passing/returning non-owned strings. In this case, because it could
// point directly at a string literal/constant, it would allow us to avoid
// creating a full std::string (and the annoyance of needing NoDestructor)
// just to store empty.
const std::string& AddressList::GetCanonicalName() const {
static const base::NoDestructor<std::string> nullstring_result;
return dns_aliases_.size() >= 1 ? dns_aliases_.front() : *nullstring_result;
}
void AddressList::SetDefaultCanonicalName() {
DCHECK(!empty());
DCHECK(dns_aliases_.empty());
SetDnsAliases({front().ToStringWithoutPort()});
}
void AddressList::SetDnsAliases(std::vector<std::string> 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<std::string>({""})) {
dns_aliases_ = std::vector<std::string>();
return;
}
dns_aliases_ = std::move(aliases);
}
void AddressList::AppendDnsAliases(std::vector<std::string> aliases) {
DCHECK(aliases != std::vector<std::string>({""}));
using iter_t = std::vector<std::string>::iterator;
dns_aliases_.insert(dns_aliases_.end(),
std::move_iterator<iter_t>(aliases.begin()),
std::move_iterator<iter_t>(aliases.end()));
}
base::Value AddressList::NetLogParams() const {
base::Value dict(base::Value::Type::DICTIONARY);
base::Value list(base::Value::Type::LIST);
for (const auto& ip_endpoint : *this)
list.Append(ip_endpoint.ToString());
dict.SetKey("address_list", std::move(list));
dict.SetStringKey("canonical_name", GetCanonicalName());
return dict;
}
void AddressList::Deduplicate() {
if (size() > 1) {
std::vector<std::pair<IPEndPoint, int>> make_me_into_a_map(size());
for (auto& addr : *this)
make_me_into_a_map.emplace_back(addr, 0);
base::flat_map<IPEndPoint, int> inserted(std::move(make_me_into_a_map));
std::vector<IPEndPoint> 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