blob: 7612a3ef6993992a4a5fff0a25e09f2d59045db1 [file] [log] [blame]
Vince Lehmanc439d662015-04-27 10:56:00 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Nick Gordonfeae5572017-01-13 12:06:26 -06003 * Copyright (c) 2014-2017, The University of Memphis,
Vince Lehmanc439d662015-04-27 10:56:00 -05004 * Regents of the University of California,
5 * Arizona Board of Regents.
6 *
7 * This file is part of NLSR (Named-data Link State Routing).
8 * See AUTHORS.md for complete list of NLSR authors and contributors.
9 *
10 * NLSR is free software: you can redistribute it and/or modify it under the terms
11 * of the GNU General Public License as published by the Free Software Foundation,
12 * either version 3 of the License, or (at your option) any later version.
13 *
14 * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
15 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 * PURPOSE. See the GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * NLSR, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
20 **/
21
22#include "nlsrc.hpp"
23
24#include "version.hpp"
Nick Gordon114537f2017-08-09 14:51:37 -050025#include "src/publisher/lsdb-dataset-interest-handler.hpp"
Vince Lehmanc439d662015-04-27 10:56:00 -050026
27#include <ndn-cxx/face.hpp>
28#include <ndn-cxx/data.hpp>
29#include <ndn-cxx/interest.hpp>
30#include <ndn-cxx/encoding/block.hpp>
Junxiao Shi3e5120c2016-09-10 16:58:34 +000031#include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
32#include <ndn-cxx/mgmt/nfd/control-response.hpp>
Vince Lehmanc439d662015-04-27 10:56:00 -050033#include <ndn-cxx/util/segment-fetcher.hpp>
34
35#include <iostream>
36
37namespace nlsrc {
38
39const ndn::Name Nlsrc::LOCALHOST_PREFIX = ndn::Name("/localhost/nlsr");
40const ndn::Name Nlsrc::LSDB_PREFIX = ndn::Name(Nlsrc::LOCALHOST_PREFIX).append("lsdb");
41const ndn::Name Nlsrc::NAME_UPDATE_PREFIX = ndn::Name(Nlsrc::LOCALHOST_PREFIX).append("prefix-update");
42
43const uint32_t Nlsrc::ERROR_CODE_TIMEOUT = 10060;
44const uint32_t Nlsrc::RESPONSE_CODE_SUCCESS = 200;
45
46Nlsrc::Nlsrc(ndn::Face& face)
47 : m_face(face)
48{
49}
50
51void
52Nlsrc::printUsage()
53{
54 std::cout << "Usage:\n" << programName << " [-h] [-V] COMMAND [<Command Options>]\n"
55 " -h print usage and exit\n"
56 " -V print version and exit\n"
57 "\n"
58 " COMMAND can be one of the following:\n"
59 " status\n"
60 " display NLSR status\n"
61 " advertise name\n"
62 " advertise a name prefix through NLSR\n"
63 " withdraw name\n"
64 " remove a name prefix advertised through NLSR"
65 << std::endl;
66}
67
68void
69Nlsrc::getStatus()
70{
71 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchAdjacencyLsas, this));
72 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchCoordinateLsas, this));
73 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchNameLsas, this));
74 m_fetchSteps.push_back(std::bind(&Nlsrc::printLsdb, this));
75
76 runNextStep();
77}
78
79bool
80Nlsrc::dispatch(const std::string& command)
81{
82 if (command == "advertise") {
83 if (nOptions != 1) {
84 return false;
85 }
86
87 advertiseName();
88 return true;
89 }
90 else if (command == "withdraw") {
91 if (nOptions != 1) {
92 return false;
93 }
94
95 withdrawName();
96 return true;
97 }
98 else if (command == "status") {
99 if (nOptions != 0) {
100 return false;
101 }
102
103 getStatus();
104 return true;
105 }
106
107 return false;
108}
109
110void
111Nlsrc::runNextStep()
112{
113 if (m_fetchSteps.empty()) {
114 return;
115 }
116
117 std::function<void()> nextStep = m_fetchSteps.front();
118 m_fetchSteps.pop_front();
119
120 nextStep();
121}
122
123void
124Nlsrc::advertiseName()
125{
126 ndn::Name name = commandLineArguments[0];
127 ndn::Name::Component verb("advertise");
128 std::string info = "(Advertise: " + name.toUri() + ")";
129
130 sendNamePrefixUpdate(name, verb, info);
131}
132
133void
134Nlsrc::withdrawName()
135{
136 ndn::Name name = commandLineArguments[0];
137 ndn::Name::Component verb("withdraw");
138 std::string info = "(Withdraw: " + name.toUri() + ")";
139
140 sendNamePrefixUpdate(name, verb, info);
141}
142
143void
144Nlsrc::sendNamePrefixUpdate(const ndn::Name& name,
145 const ndn::Name::Component& verb,
146 const std::string& info)
147{
148 ndn::nfd::ControlParameters parameters;
149 parameters.setName(name);
150
151 ndn::Name commandName = NAME_UPDATE_PREFIX;
152 commandName.append(verb);
153
154 ndn::Interest interest(commandName.append(parameters.wireEncode()));
155 interest.setMustBeFresh(true);
156 m_keyChain.sign(interest);
157
158 m_face.expressInterest(interest,
159 std::bind(&Nlsrc::onControlResponse, this, info, _2),
Alexander Afanasyev1de901f2017-03-09 12:43:57 -0800160 std::bind(&Nlsrc::onTimeout, this, ERROR_CODE_TIMEOUT, "Nack"),
Vince Lehmanc439d662015-04-27 10:56:00 -0500161 std::bind(&Nlsrc::onTimeout, this, ERROR_CODE_TIMEOUT, "Timeout"));
162}
163
164void
165Nlsrc::onControlResponse(const std::string& info, const ndn::Data& data)
166{
Vince Lehmand33e5bc2015-06-22 15:27:50 -0500167 if (data.getMetaInfo().getType() == ndn::tlv::ContentType_Nack) {
168 std::cerr << "ERROR: Run-time advertise/withdraw disabled" << std::endl;
169 return;
170 }
171
Vince Lehmanc439d662015-04-27 10:56:00 -0500172 ndn::nfd::ControlResponse response;
173
174 try {
175 response.wireDecode(data.getContent().blockFromValue());
176 }
177 catch (const std::exception& e) {
178 std::cerr << "ERROR: Control response decoding error" << std::endl;
179 return;
180 }
181
182 uint32_t code = response.getCode();
183
184 if (code != RESPONSE_CODE_SUCCESS) {
185 std::cerr << "Name prefix update error (code: " << code << ")" << std::endl;
186 return;
187 }
188
189 std::cout << "Applied Name prefix update successfully: " << info << std::endl;
190}
191
192void
193Nlsrc::fetchAdjacencyLsas()
194{
Nick Gordon114537f2017-08-09 14:51:37 -0500195 fetchFromLsdb<nlsr::tlv::AdjacencyLsa>(nlsr::dataset::ADJACENCY_COMPONENT,
Vince Lehmanc439d662015-04-27 10:56:00 -0500196 std::bind(&Nlsrc::recordAdjacencyLsa, this, _1));
197}
198
199void
200Nlsrc::fetchCoordinateLsas()
201{
Nick Gordon114537f2017-08-09 14:51:37 -0500202 fetchFromLsdb<nlsr::tlv::CoordinateLsa>(nlsr::dataset::COORDINATE_COMPONENT,
Vince Lehmanc439d662015-04-27 10:56:00 -0500203 std::bind(&Nlsrc::recordCoordinateLsa, this, _1));
204}
205
206void
207Nlsrc::fetchNameLsas()
208{
Nick Gordon114537f2017-08-09 14:51:37 -0500209 fetchFromLsdb<nlsr::tlv::NameLsa>(nlsr::dataset::NAME_COMPONENT,
Vince Lehmanc439d662015-04-27 10:56:00 -0500210 std::bind(&Nlsrc::recordNameLsa, this, _1));
211}
212
213template <class T>
214void
215Nlsrc::fetchFromLsdb(const ndn::Name::Component& datasetType,
216 const std::function<void(const T&)>& recordLsa)
217{
218 ndn::Name command = LSDB_PREFIX;
219 command.append(datasetType);
220
221 ndn::Interest interest(command);
222
223 ndn::util::SegmentFetcher::fetch(m_face,
224 interest,
Muktadir R Chowdhury4c7caad2015-09-03 15:49:22 -0500225 m_validator,
Vince Lehmanc439d662015-04-27 10:56:00 -0500226 std::bind(&Nlsrc::onFetchSuccess<T>,
227 this, _1, recordLsa),
228 std::bind(&Nlsrc::onTimeout, this, _1, _2));
229}
230
231template <class T>
232void
233Nlsrc::onFetchSuccess(const ndn::ConstBufferPtr& data,
234 const std::function<void(const T&)>& recordLsa)
235{
236 ndn::Block block;
237 size_t offset = 0;
238
239 while (offset < data->size()) {
240 bool isOk = false;
241 std::tie(isOk, block) = ndn::Block::fromBuffer(data, offset);
242
243 if (!isOk) {
244 std::cerr << "ERROR: cannot decode LSA TLV" << std::endl;
245 break;
246 }
247
248 offset += block.size();
249
250 T lsa(block);
251 recordLsa(lsa);
252 }
253
254 runNextStep();
255}
256
257void
258Nlsrc::onTimeout(uint32_t errorCode, const std::string& error)
259{
260 std::cerr << "Request timed out (code: " << errorCode
261 << ", error: " << error << ")" << std::endl;
262}
263
264std::string
265Nlsrc::getLsaInfoString(const nlsr::tlv::LsaInfo& info)
266{
267 std::ostringstream os;
268 os << " info=" << info;
269
270 return os.str();
271}
272
273void
274Nlsrc::recordAdjacencyLsa(const nlsr::tlv::AdjacencyLsa& lsa)
275{
276 Router& router = getRouter(lsa.getLsaInfo());
277
278 std::ostringstream os;
279 os << " AdjacencyLsa:" << std::endl;
280
281 os << getLsaInfoString(lsa.getLsaInfo()) << std::endl;
282
283 for (const auto& adjacency : lsa.getAdjacencies()) {
284 os << " adjacency=" << adjacency << std::endl;
285 }
286
287 router.adjacencyLsaString = os.str();
288}
289
290void
291Nlsrc::recordCoordinateLsa(const nlsr::tlv::CoordinateLsa& lsa)
292{
293 Router& router = getRouter(lsa.getLsaInfo());
294
295 std::ostringstream os;
296 os << " Coordinate LSA:" << std::endl;
297
298 os << getLsaInfoString(lsa.getLsaInfo()) << std::endl;
299
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600300 int i = 0;
301 for (auto const& value: lsa.getHyperbolicAngle()) {
302 os << " Hyp Angle " << i++ << ": "<< value << " ";
303 }
304 os << "\n radius=" << lsa.getHyperbolicRadius() << std::endl;
Vince Lehmanc439d662015-04-27 10:56:00 -0500305
306 router.coordinateLsaString = os.str();
307}
308
309void
310Nlsrc::recordNameLsa(const nlsr::tlv::NameLsa& lsa)
311{
312 Router& router = getRouter(lsa.getLsaInfo());
313
314 std::ostringstream os;
315 os << " Name LSA:" << std::endl;
316
317 os << getLsaInfoString(lsa.getLsaInfo()) << std::endl;
318
319 for (const auto& name : lsa.getNames()) {
320 os << " name=" << name << std::endl;
321 }
322
323 router.nameLsaString = os.str();
324}
325
326void
327Nlsrc::printLsdb()
328{
329 std::cout << "NLSR Status" << std::endl;
330 std::cout << "LSDB:" << std::endl;
331
332 for (const auto& item : m_routers) {
333 std::cout << " OriginRouter: " << item.first << std::endl;
334 std::cout << std::endl;
335
336 const Router& router = item.second;
337
338 if (!router.adjacencyLsaString.empty()) {
339 std::cout << router.adjacencyLsaString << std::endl;
340 }
341
342 if (!router.coordinateLsaString.empty()) {
343 std::cout << router.coordinateLsaString << std::endl;
344 }
345
346 if (!router.nameLsaString.empty()) {
347 std::cout << router.nameLsaString << std::endl;
348 }
349 }
350}
351
352Nlsrc::Router&
353Nlsrc::getRouter(const nlsr::tlv::LsaInfo& info)
354{
355 const ndn::Name& originRouterName = info.getOriginRouter();
356
357 const auto& pair =
Alexander Afanasyevf9f39102015-12-01 17:43:40 -0800358 m_routers.insert(std::make_pair(originRouterName, Router()));
Vince Lehmanc439d662015-04-27 10:56:00 -0500359
360 return pair.first->second;
361}
362
363} // namespace nlsrc
364
365////////////////////////////////////////////////////////////////////////////////
366////////////////////////////////////////////////////////////////////////////////
367
368int
369main(int argc, char** argv)
370{
371 ndn::Face face;
372 nlsrc::Nlsrc nlsrc(face);
373
374 nlsrc.programName = argv[0];
375
376 if (argc < 2) {
377 nlsrc.printUsage();
378 return 0;
379 }
380
381 int opt;
382 while ((opt = ::getopt(argc, argv, "hV")) != -1) {
383 switch (opt) {
384 case 'h':
385 nlsrc.printUsage();
386 return 0;
387 case 'V':
388 std::cout << NLSR_VERSION_BUILD_STRING << std::endl;
389 return 0;
390 default:
391 nlsrc.printUsage();
392 return 1;
393 }
394 }
395
396 if (argc == ::optind) {
397 nlsrc.printUsage();
398 return 1;
399 }
400
401 try {
402 ::optind = 2; // Set ::optind to the command's index
403
404 nlsrc.commandLineArguments = argv + ::optind;
405 nlsrc.nOptions = argc - ::optind;
406
407 // argv[1] points to the command, so pass it to the dispatch
408 bool isOk = nlsrc.dispatch(argv[1]);
409 if (!isOk) {
410 nlsrc.printUsage();
411 return 1;
412 }
413
414 face.processEvents();
415 }
416 catch (const std::exception& e) {
417 std::cerr << "ERROR: " << e.what() << std::endl;
418 return 2;
419 }
420 return 0;
Alexander Afanasyevf9f39102015-12-01 17:43:40 -0800421}