| // 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 |