/ src / nodeinfo.cpp
nodeinfo.cpp
  1  // SPDX-FileCopyrightText: Copyright (C) 2024-2025 Marek Küthe <m.k@mk16.de>
  2  //
  3  // SPDX-License-Identifier: GPL-3.0-or-later
  4  
  5  #include "nodeinfo.hpp"
  6  
  7  using namespace crazytrace;
  8  
  9  crazytrace::NodeInfo::NodeInfo() :
 10      _hoplimit(64),
 11      _randomgenerator(0),
 12      _addressadded(false)
 13  {
 14  }
 15  
 16  uint8_t crazytrace::NodeInfo::get_hoplimit() const noexcept
 17  {
 18      return this->_hoplimit;
 19  }
 20  
 21  void crazytrace::NodeInfo::set_mac_address(
 22      Tins::HWAddress<6> mac_address) noexcept
 23  {
 24      this->_mac_address = mac_address;
 25  }
 26  
 27  const Tins::HWAddress<6>& crazytrace::NodeInfo::get_mac_address() const noexcept
 28  {
 29      return this->_mac_address;
 30  }
 31  
 32  bool crazytrace::NodeInfo::has_address(const Tins::IPv6Address& address)
 33  {
 34      return std::ranges::binary_search(this->_addresses, address);
 35  }
 36  
 37  void crazytrace::NodeInfo::set_hoplimit(uint8_t hoplimit)
 38  {
 39      static_assert(std::numeric_limits<decltype(this->_hoplimit)>::min() == 0);
 40      static_assert(std::numeric_limits<decltype(this->_hoplimit)>::max() == 255);
 41      this->_hoplimit = hoplimit;
 42  }
 43  
 44  void crazytrace::NodeInfo::add_node(std::shared_ptr<NodeInfo> node)
 45  {
 46      this->_nodes.push_back(node);
 47  }
 48  
 49  void crazytrace::NodeInfo::add_address(Tins::IPv6Address address)
 50  {
 51      this->_addressadded = true;
 52      this->_addresses.push_back(address);
 53  }
 54  
 55  const Tins::IPv6Address& crazytrace::NodeInfo::get_address()
 56  {
 57      if (this->_addressadded)
 58      {
 59          /* Is called up each time the number of addresses is changed. However,
 60             it is not called after each address is added to allow multiple
 61             addresses to be added quickly. */
 62          std::size_t max_address = this->_addresses.size();
 63          if (max_address == 0)
 64              throw std::invalid_argument(
 65                  "Despite adding an address, none is available.");
 66          max_address--;
 67  
 68          this->_randomgenerator = RandomGenerator(max_address);
 69          std::ranges::sort(this->_addresses);
 70          this->_addressadded = false;
 71      }
 72      const std::size_t address_number = this->_randomgenerator.generate();
 73      return this->_addresses.at(address_number);
 74  }
 75  
 76  std::size_t crazytrace::NodeInfo::max_depth() const
 77  {
 78      std::size_t max = 0;
 79      for (const auto& node : this->_nodes)
 80      {
 81          const std::size_t node_depth = node->max_depth();
 82          max = std::max(max, node_depth);
 83      }
 84      return max + 1;
 85  }
 86  
 87  std::vector<std::shared_ptr<NodeInfo>> crazytrace::NodeInfo::get_route_to(
 88      const Tins::IPv6Address& destination_address) const
 89  {
 90      for (const auto& node : this->_nodes)
 91      {
 92          if (node->has_address(destination_address))
 93          {
 94              std::vector<std::shared_ptr<NodeInfo>> result;
 95              result.push_back(node);
 96              return result;
 97          }
 98  
 99          std::vector<std::shared_ptr<NodeInfo>> result =
100              node->get_route_to(destination_address);
101          if (!result.empty())
102          {
103              result.push_back(node);
104              return result;
105          }
106      }
107  
108      return {};
109  }
110  
111  void crazytrace::NodeInfo::print(std::ostream& os, unsigned int layer) const
112  {
113      const std::string tabs(layer, '\t');
114  
115      os << tabs << *this << std::endl;
116      if (!this->_nodes.empty())
117      {
118          os << tabs << "Childs:" << std::endl;
119          for (const auto& node : this->_nodes)
120          {
121              node->print(os, layer + 1);
122          }
123      }
124  }
125  
126  bool crazytrace::NodeInfo::operator==(const NodeInfo& other) const
127  {
128      return this->_addresses == other._addresses &&
129             this->_mac_address == other._mac_address &&
130             this->_hoplimit == other._hoplimit &&
131             std::ranges::equal(this->_nodes, // flawfinder: ignore
132                                other._nodes,
133                                [](const auto& a, const auto& b)
134                                {
135                                    return *a == *b;
136                                });
137  }
138  
139  std::ostream& crazytrace::operator<<(std::ostream& os,
140                                       NodeInfo const & nodeinfo)
141  {
142      os << "NodeInfo: hoplimit=" << static_cast<unsigned>(nodeinfo._hoplimit);
143      for (const auto& address : nodeinfo._addresses)
144      {
145          os << " " << address;
146      }
147      if (nodeinfo._mac_address != Tins::HWAddress<6>())
148      {
149          /* Is not empty address? */
150          os << " " << nodeinfo._mac_address;
151      }
152  
153      return os;
154  }