hello-protocol.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2022, The University of Memphis,
4  * Regents of the University of California
5  *
6  * This file is part of NLSR (Named-data Link State Routing).
7  * See AUTHORS.md for complete list of NLSR authors and contributors.
8  *
9  * NLSR is free software: you can redistribute it and/or modify it under the terms
10  * of the GNU General Public License as published by the Free Software Foundation,
11  * either version 3 of the License, or (at your option) any later version.
12  *
13  * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
14  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along with
18  * NLSR, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "hello-protocol.hpp"
22 #include "nlsr.hpp"
23 #include "lsdb.hpp"
24 #include "logger.hpp"
25 #include "utility/name-helper.hpp"
26 
27 #include <ndn-cxx/encoding/nfd-constants.hpp>
28 
29 namespace nlsr {
30 
31 INIT_LOGGER(HelloProtocol);
32 
33 HelloProtocol::HelloProtocol(ndn::Face& face, ndn::KeyChain& keyChain,
34  ConfParameter& confParam, RoutingTable& routingTable,
35  Lsdb& lsdb)
36  : m_face(face)
37  , m_scheduler(m_face.getIoService())
38  , m_keyChain(keyChain)
39  , m_signingInfo(confParam.getSigningInfo())
40  , m_confParam(confParam)
41  , m_routingTable(routingTable)
42  , m_lsdb(lsdb)
43  , m_adjacencyList(m_confParam.getAdjacencyList())
44 {
45  ndn::Name name(m_confParam.getRouterPrefix());
46  name.append(NLSR_COMPONENT);
47  name.append(INFO_COMPONENT);
48 
49  NLSR_LOG_DEBUG("Setting interest filter for Hello interest: " << name);
50 
51  m_face.setInterestFilter(ndn::InterestFilter(name).allowLoopback(false),
52  [this] (const auto& name, const auto& interest) {
53  processInterest(name, interest);
54  },
55  [] (const auto& name) {
56  NLSR_LOG_DEBUG("Successfully registered prefix: " << name);
57  },
58  [] (const auto& name, const auto& resp) {
59  NLSR_LOG_ERROR("Failed to register prefix " << name);
60  NDN_THROW(std::runtime_error("Failed to register hello prefix: " + resp));
61  },
62  m_signingInfo, ndn::nfd::ROUTE_FLAG_CAPTURE);
63 }
64 
65 void
66 HelloProtocol::expressInterest(const ndn::Name& interestName, uint32_t seconds)
67 {
68  NLSR_LOG_DEBUG("Expressing Interest: " << interestName);
69  ndn::Interest interest(interestName);
70  interest.setInterestLifetime(ndn::time::seconds(seconds));
71  interest.setMustBeFresh(true);
72  interest.setCanBePrefix(true);
73  m_face.expressInterest(interest,
74  std::bind(&HelloProtocol::onContent, this, _1, _2),
75  [this, seconds] (const ndn::Interest& interest, const ndn::lp::Nack& nack)
76  {
77  NDN_LOG_TRACE("Received Nack with reason: " << nack.getReason());
78  NDN_LOG_TRACE("Will treat as timeout in " << 2 * seconds << " seconds");
79  m_scheduler.schedule(ndn::time::seconds(2 * seconds),
80  [this, interest] { processInterestTimedOut(interest); });
81  },
82  std::bind(&HelloProtocol::processInterestTimedOut, this, _1));
83 
84  // increment SENT_HELLO_INTEREST
86 }
87 
88 void
89 HelloProtocol::sendHelloInterest(const ndn::Name& neighbor)
90 {
91  auto adjacent = m_adjacencyList.findAdjacent(neighbor);
92 
93  if (adjacent == m_adjacencyList.end()) {
94  return;
95  }
96 
97  // If this adjacency has a Face, just proceed as usual.
98  if(adjacent->getFaceId() != 0) {
99  // interest name: /<neighbor>/NLSR/INFO/<router>
100  ndn::Name interestName = adjacent->getName() ;
101  interestName.append(NLSR_COMPONENT);
102  interestName.append(INFO_COMPONENT);
103  interestName.append(ndn::tlv::GenericNameComponent, m_confParam.getRouterPrefix().wireEncode());
104  expressInterest(interestName, m_confParam.getInterestResendTime());
105  NLSR_LOG_DEBUG("Sending HELLO interest: " << interestName);
106  }
107 
108  m_scheduler.schedule(ndn::time::seconds(m_confParam.getInfoInterestInterval()),
109  [this, neighbor] { sendHelloInterest(neighbor); });
110 }
111 
112 void
113 HelloProtocol::processInterest(const ndn::Name& name,
114  const ndn::Interest& interest)
115 {
116  // interest name: /<neighbor>/NLSR/INFO/<router>
117  const ndn::Name interestName = interest.getName();
118 
119  // increment RCV_HELLO_INTEREST
121 
122  NLSR_LOG_DEBUG("Interest Received for Name: " << interestName);
123  if (interestName.get(-2).toUri() != INFO_COMPONENT) {
124  NLSR_LOG_DEBUG("INFO_COMPONENT not found or interestName: " << interestName
125  << " does not match expression");
126  return;
127  }
128 
129  ndn::Name neighbor;
130  neighbor.wireDecode(interestName.get(-1).blockFromValue());
131  NLSR_LOG_DEBUG("Neighbor: " << neighbor);
132  if (m_adjacencyList.isNeighbor(neighbor)) {
133  std::shared_ptr<ndn::Data> data = std::make_shared<ndn::Data>();
134  data->setName(ndn::Name(interest.getName()).appendVersion());
135  data->setFreshnessPeriod(ndn::time::seconds(10)); // 10 sec
136  data->setContent(ndn::make_span(reinterpret_cast<const uint8_t*>(INFO_COMPONENT.data()),
137  INFO_COMPONENT.size()));
138 
139  m_keyChain.sign(*data, m_signingInfo);
140 
141  NLSR_LOG_DEBUG("Sending out data for name: " << interest.getName());
142 
143  m_face.put(*data);
144  // increment SENT_HELLO_DATA
146 
147  auto adjacent = m_adjacencyList.findAdjacent(neighbor);
148  // If this neighbor was previously inactive, send our own hello interest, too
149  if (adjacent->getStatus() == Adjacent::STATUS_INACTIVE) {
150  // We can only do that if the neighbor currently has a face.
151  if(adjacent->getFaceId() != 0){
152  // interest name: /<neighbor>/NLSR/INFO/<router>
153  ndn::Name interestName(neighbor);
154  interestName.append(NLSR_COMPONENT);
155  interestName.append(INFO_COMPONENT);
156  interestName.append(ndn::tlv::GenericNameComponent, m_confParam.getRouterPrefix().wireEncode());
157  expressInterest(interestName, m_confParam.getInterestResendTime());
158  }
159  }
160  }
161 }
162 
163 void
164 HelloProtocol::processInterestTimedOut(const ndn::Interest& interest)
165 {
166  // interest name: /<neighbor>/NLSR/INFO/<router>
167  const ndn::Name interestName(interest.getName());
168  NLSR_LOG_DEBUG("Interest timed out for Name: " << interestName);
169  if (interestName.get(-2).toUri() != INFO_COMPONENT) {
170  return;
171  }
172  ndn::Name neighbor = interestName.getPrefix(-3);
173  NLSR_LOG_DEBUG("Neighbor: " << neighbor);
174  m_adjacencyList.incrementTimedOutInterestCount(neighbor);
175 
176  Adjacent::Status status = m_adjacencyList.getStatusOfNeighbor(neighbor);
177 
178  uint32_t infoIntTimedOutCount = m_adjacencyList.getTimedOutInterestCount(neighbor);
179  NLSR_LOG_DEBUG("Status: " << status);
180  NLSR_LOG_DEBUG("Info Interest Timed out: " << infoIntTimedOutCount);
181  if (infoIntTimedOutCount < m_confParam.getInterestRetryNumber()) {
182  // interest name: /<neighbor>/NLSR/INFO/<router>
183  ndn::Name interestName(neighbor);
184  interestName.append(NLSR_COMPONENT);
185  interestName.append(INFO_COMPONENT);
186  interestName.append(ndn::tlv::GenericNameComponent, m_confParam.getRouterPrefix().wireEncode());
187  NLSR_LOG_DEBUG("Resending interest: " << interestName);
188  expressInterest(interestName, m_confParam.getInterestResendTime());
189  }
190  else if (status == Adjacent::STATUS_ACTIVE) {
191  m_adjacencyList.setStatusOfNeighbor(neighbor, Adjacent::STATUS_INACTIVE);
192 
193  NLSR_LOG_DEBUG("Neighbor: " << neighbor << " status changed to INACTIVE");
194 
195  if (m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_ON) {
196  m_routingTable.scheduleRoutingTableCalculation();
197  }
198  else {
199  m_lsdb.scheduleAdjLsaBuild();
200  }
201  }
202 }
203 
204 // This is the first function that incoming Hello data will
205 // see. This checks if the data appears to be signed, and passes it
206 // on to validate the content of the data.
207 void
208 HelloProtocol::onContent(const ndn::Interest& interest, const ndn::Data& data)
209 {
210  NLSR_LOG_DEBUG("Received data for INFO(name): " << data.getName());
211  auto kl = data.getKeyLocator();
212  if (kl && kl->getType() == ndn::tlv::Name) {
213  NLSR_LOG_DEBUG("Data signed with: " << kl->getName());
214  }
215  m_confParam.getValidator().validate(data,
216  std::bind(&HelloProtocol::onContentValidated, this, _1),
217  std::bind(&HelloProtocol::onContentValidationFailed,
218  this, _1, _2));
219 }
220 
221 void
222 HelloProtocol::onContentValidated(const ndn::Data& data)
223 {
224  // data name: /<neighbor>/NLSR/INFO/<router>/<version>
225  ndn::Name dataName = data.getName();
226  NLSR_LOG_DEBUG("Data validation successful for INFO(name): " << dataName);
227 
228  if (dataName.get(-3).toUri() == INFO_COMPONENT) {
229  ndn::Name neighbor = dataName.getPrefix(-4);
230 
231  Adjacent::Status oldStatus = m_adjacencyList.getStatusOfNeighbor(neighbor);
232  m_adjacencyList.setStatusOfNeighbor(neighbor, Adjacent::STATUS_ACTIVE);
233  m_adjacencyList.setTimedOutInterestCount(neighbor, 0);
234  Adjacent::Status newStatus = m_adjacencyList.getStatusOfNeighbor(neighbor);
235 
236  NLSR_LOG_DEBUG("Neighbor : " << neighbor);
237  NLSR_LOG_DEBUG("Old Status: " << oldStatus << " New Status: " << newStatus);
238  // change in Adjacency list
239  if ((oldStatus - newStatus) != 0) {
240  if (m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_ON) {
241  m_routingTable.scheduleRoutingTableCalculation();
242  }
243  else {
244  m_lsdb.scheduleAdjLsaBuild();
245  }
246  onInitialHelloDataValidated(neighbor);
247  }
248  }
249  // increment RCV_HELLO_DATA
251 }
252 
253 void
254 HelloProtocol::onContentValidationFailed(const ndn::Data& data,
255  const ndn::security::ValidationError& ve)
256 {
257  NLSR_LOG_DEBUG("Validation Error: " << ve);
258 }
259 
260 } // namespace nlsr
int32_t getTimedOutInterestCount(const ndn::Name &neighbor) const
void incrementTimedOutInterestCount(const ndn::Name &neighbor)
void setTimedOutInterestCount(const ndn::Name &neighbor, uint32_t count)
const_iterator end() const
Adjacent::Status getStatusOfNeighbor(const ndn::Name &neighbor) const
bool isNeighbor(const ndn::Name &adjName) const
void setStatusOfNeighbor(const ndn::Name &neighbor, Adjacent::Status status)
AdjacencyList::iterator findAdjacent(const ndn::Name &adjName)
A class to house all the configuration parameters for NLSR.
uint32_t getInfoInterestInterval() const
int32_t getHyperbolicState() const
uint32_t getInterestRetryNumber() const
const ndn::Name & getRouterPrefix() const
uint32_t getInterestResendTime() const
ndn::security::ValidatorConfig & getValidator()
HelloProtocol(ndn::Face &face, ndn::KeyChain &keyChain, ConfParameter &confParam, RoutingTable &routingTable, Lsdb &lsdb)
void sendHelloInterest(const ndn::Name &neighbor)
Sends Hello Interests to all neighbors.
static const std::string INFO_COMPONENT
static const std::string NLSR_COMPONENT
void processInterest(const ndn::Name &name, const ndn::Interest &interest)
Processes a Hello Interest from a neighbor.
void expressInterest(const ndn::Name &interestNamePrefix, uint32_t seconds)
Sends a Hello Interest packet.
ndn::util::Signal< HelloProtocol, const ndn::Name & > onInitialHelloDataValidated
ndn::util::Signal< HelloProtocol, Statistics::PacketType > hpIncrementSignal
void scheduleAdjLsaBuild()
Schedules a build of this router's LSA.
Definition: lsdb.cpp:115
void scheduleRoutingTableCalculation()
Schedules a calculation event in the event scheduler only if one isn't already scheduled.
Copyright (c) 2014-2018, The University of Memphis, Regents of the University of California.
#define NLSR_LOG_DEBUG(x)
Definition: logger.hpp:38
#define INIT_LOGGER(name)
Definition: logger.hpp:35
#define NLSR_LOG_ERROR(x)
Definition: logger.hpp:41
Copyright (c) 2014-2020, The University of Memphis, Regents of the University of California.
@ HYPERBOLIC_STATE_ON