blob: 103fa2610583d286b02ae1c814289336c326d6e1 [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>
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -050034#include <ndn-cxx/security/key-chain.hpp>
35#include <ndn-cxx/security/command-interest-signer.hpp>
Vince Lehmanc439d662015-04-27 10:56:00 -050036
37#include <iostream>
38
39namespace nlsrc {
40
41const ndn::Name Nlsrc::LOCALHOST_PREFIX = ndn::Name("/localhost/nlsr");
42const ndn::Name Nlsrc::LSDB_PREFIX = ndn::Name(Nlsrc::LOCALHOST_PREFIX).append("lsdb");
43const ndn::Name Nlsrc::NAME_UPDATE_PREFIX = ndn::Name(Nlsrc::LOCALHOST_PREFIX).append("prefix-update");
44
45const uint32_t Nlsrc::ERROR_CODE_TIMEOUT = 10060;
46const uint32_t Nlsrc::RESPONSE_CODE_SUCCESS = 200;
47
48Nlsrc::Nlsrc(ndn::Face& face)
49 : m_face(face)
50{
51}
52
53void
54Nlsrc::printUsage()
55{
56 std::cout << "Usage:\n" << programName << " [-h] [-V] COMMAND [<Command Options>]\n"
57 " -h print usage and exit\n"
58 " -V print version and exit\n"
59 "\n"
60 " COMMAND can be one of the following:\n"
61 " status\n"
62 " display NLSR status\n"
63 " advertise name\n"
64 " advertise a name prefix through NLSR\n"
65 " withdraw name\n"
66 " remove a name prefix advertised through NLSR"
67 << std::endl;
68}
69
70void
71Nlsrc::getStatus()
72{
73 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchAdjacencyLsas, this));
74 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchCoordinateLsas, this));
75 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchNameLsas, this));
76 m_fetchSteps.push_back(std::bind(&Nlsrc::printLsdb, this));
77
78 runNextStep();
79}
80
81bool
82Nlsrc::dispatch(const std::string& command)
83{
84 if (command == "advertise") {
85 if (nOptions != 1) {
86 return false;
87 }
88
89 advertiseName();
90 return true;
91 }
92 else if (command == "withdraw") {
93 if (nOptions != 1) {
94 return false;
95 }
96
97 withdrawName();
98 return true;
99 }
100 else if (command == "status") {
101 if (nOptions != 0) {
102 return false;
103 }
104
105 getStatus();
106 return true;
107 }
108
109 return false;
110}
111
112void
113Nlsrc::runNextStep()
114{
115 if (m_fetchSteps.empty()) {
116 return;
117 }
118
119 std::function<void()> nextStep = m_fetchSteps.front();
120 m_fetchSteps.pop_front();
121
122 nextStep();
123}
124
125void
126Nlsrc::advertiseName()
127{
128 ndn::Name name = commandLineArguments[0];
129 ndn::Name::Component verb("advertise");
130 std::string info = "(Advertise: " + name.toUri() + ")";
131
132 sendNamePrefixUpdate(name, verb, info);
133}
134
135void
136Nlsrc::withdrawName()
137{
138 ndn::Name name = commandLineArguments[0];
139 ndn::Name::Component verb("withdraw");
140 std::string info = "(Withdraw: " + name.toUri() + ")";
141
142 sendNamePrefixUpdate(name, verb, info);
143}
144
145void
146Nlsrc::sendNamePrefixUpdate(const ndn::Name& name,
147 const ndn::Name::Component& verb,
148 const std::string& info)
149{
150 ndn::nfd::ControlParameters parameters;
151 parameters.setName(name);
152
153 ndn::Name commandName = NAME_UPDATE_PREFIX;
154 commandName.append(verb);
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -0500155 commandName.append(parameters.wireEncode());
Vince Lehmanc439d662015-04-27 10:56:00 -0500156
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -0500157 ndn::security::CommandInterestSigner cis(m_keyChain);
Vince Lehmanc439d662015-04-27 10:56:00 -0500158
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -0500159 ndn::Interest commandInterest =
160 cis.makeCommandInterest(commandName,
161 ndn::security::signingByIdentity(m_keyChain.getPib().
162 getDefaultIdentity()));
163
164 commandInterest.setMustBeFresh(true);
165
166 m_face.expressInterest(commandInterest,
Vince Lehmanc439d662015-04-27 10:56:00 -0500167 std::bind(&Nlsrc::onControlResponse, this, info, _2),
Alexander Afanasyev1de901f2017-03-09 12:43:57 -0800168 std::bind(&Nlsrc::onTimeout, this, ERROR_CODE_TIMEOUT, "Nack"),
Vince Lehmanc439d662015-04-27 10:56:00 -0500169 std::bind(&Nlsrc::onTimeout, this, ERROR_CODE_TIMEOUT, "Timeout"));
170}
171
172void
173Nlsrc::onControlResponse(const std::string& info, const ndn::Data& data)
174{
Vince Lehmand33e5bc2015-06-22 15:27:50 -0500175 if (data.getMetaInfo().getType() == ndn::tlv::ContentType_Nack) {
176 std::cerr << "ERROR: Run-time advertise/withdraw disabled" << std::endl;
177 return;
178 }
179
Vince Lehmanc439d662015-04-27 10:56:00 -0500180 ndn::nfd::ControlResponse response;
181
182 try {
183 response.wireDecode(data.getContent().blockFromValue());
184 }
185 catch (const std::exception& e) {
186 std::cerr << "ERROR: Control response decoding error" << std::endl;
187 return;
188 }
189
190 uint32_t code = response.getCode();
191
192 if (code != RESPONSE_CODE_SUCCESS) {
193 std::cerr << "Name prefix update error (code: " << code << ")" << std::endl;
194 return;
195 }
196
197 std::cout << "Applied Name prefix update successfully: " << info << std::endl;
198}
199
200void
201Nlsrc::fetchAdjacencyLsas()
202{
Nick Gordon114537f2017-08-09 14:51:37 -0500203 fetchFromLsdb<nlsr::tlv::AdjacencyLsa>(nlsr::dataset::ADJACENCY_COMPONENT,
Vince Lehmanc439d662015-04-27 10:56:00 -0500204 std::bind(&Nlsrc::recordAdjacencyLsa, this, _1));
205}
206
207void
208Nlsrc::fetchCoordinateLsas()
209{
Nick Gordon114537f2017-08-09 14:51:37 -0500210 fetchFromLsdb<nlsr::tlv::CoordinateLsa>(nlsr::dataset::COORDINATE_COMPONENT,
Vince Lehmanc439d662015-04-27 10:56:00 -0500211 std::bind(&Nlsrc::recordCoordinateLsa, this, _1));
212}
213
214void
215Nlsrc::fetchNameLsas()
216{
Nick Gordon114537f2017-08-09 14:51:37 -0500217 fetchFromLsdb<nlsr::tlv::NameLsa>(nlsr::dataset::NAME_COMPONENT,
Vince Lehmanc439d662015-04-27 10:56:00 -0500218 std::bind(&Nlsrc::recordNameLsa, this, _1));
219}
220
221template <class T>
222void
223Nlsrc::fetchFromLsdb(const ndn::Name::Component& datasetType,
224 const std::function<void(const T&)>& recordLsa)
225{
226 ndn::Name command = LSDB_PREFIX;
227 command.append(datasetType);
228
229 ndn::Interest interest(command);
230
231 ndn::util::SegmentFetcher::fetch(m_face,
232 interest,
Muktadir R Chowdhury4c7caad2015-09-03 15:49:22 -0500233 m_validator,
Vince Lehmanc439d662015-04-27 10:56:00 -0500234 std::bind(&Nlsrc::onFetchSuccess<T>,
235 this, _1, recordLsa),
236 std::bind(&Nlsrc::onTimeout, this, _1, _2));
237}
238
239template <class T>
240void
241Nlsrc::onFetchSuccess(const ndn::ConstBufferPtr& data,
242 const std::function<void(const T&)>& recordLsa)
243{
244 ndn::Block block;
245 size_t offset = 0;
246
247 while (offset < data->size()) {
248 bool isOk = false;
249 std::tie(isOk, block) = ndn::Block::fromBuffer(data, offset);
250
251 if (!isOk) {
252 std::cerr << "ERROR: cannot decode LSA TLV" << std::endl;
253 break;
254 }
255
256 offset += block.size();
257
258 T lsa(block);
259 recordLsa(lsa);
260 }
261
262 runNextStep();
263}
264
265void
266Nlsrc::onTimeout(uint32_t errorCode, const std::string& error)
267{
268 std::cerr << "Request timed out (code: " << errorCode
269 << ", error: " << error << ")" << std::endl;
270}
271
272std::string
273Nlsrc::getLsaInfoString(const nlsr::tlv::LsaInfo& info)
274{
275 std::ostringstream os;
276 os << " info=" << info;
277
278 return os.str();
279}
280
281void
282Nlsrc::recordAdjacencyLsa(const nlsr::tlv::AdjacencyLsa& lsa)
283{
284 Router& router = getRouter(lsa.getLsaInfo());
285
286 std::ostringstream os;
287 os << " AdjacencyLsa:" << std::endl;
288
289 os << getLsaInfoString(lsa.getLsaInfo()) << std::endl;
290
291 for (const auto& adjacency : lsa.getAdjacencies()) {
292 os << " adjacency=" << adjacency << std::endl;
293 }
294
295 router.adjacencyLsaString = os.str();
296}
297
298void
299Nlsrc::recordCoordinateLsa(const nlsr::tlv::CoordinateLsa& lsa)
300{
301 Router& router = getRouter(lsa.getLsaInfo());
302
303 std::ostringstream os;
304 os << " Coordinate LSA:" << std::endl;
305
306 os << getLsaInfoString(lsa.getLsaInfo()) << std::endl;
307
Muktadir R Chowdhuryb00dc2a2016-11-05 10:48:58 -0600308 int i = 0;
309 for (auto const& value: lsa.getHyperbolicAngle()) {
310 os << " Hyp Angle " << i++ << ": "<< value << " ";
311 }
312 os << "\n radius=" << lsa.getHyperbolicRadius() << std::endl;
Vince Lehmanc439d662015-04-27 10:56:00 -0500313
314 router.coordinateLsaString = os.str();
315}
316
317void
318Nlsrc::recordNameLsa(const nlsr::tlv::NameLsa& lsa)
319{
320 Router& router = getRouter(lsa.getLsaInfo());
321
322 std::ostringstream os;
323 os << " Name LSA:" << std::endl;
324
325 os << getLsaInfoString(lsa.getLsaInfo()) << std::endl;
326
327 for (const auto& name : lsa.getNames()) {
328 os << " name=" << name << std::endl;
329 }
330
331 router.nameLsaString = os.str();
332}
333
334void
335Nlsrc::printLsdb()
336{
337 std::cout << "NLSR Status" << std::endl;
338 std::cout << "LSDB:" << std::endl;
339
340 for (const auto& item : m_routers) {
341 std::cout << " OriginRouter: " << item.first << std::endl;
342 std::cout << std::endl;
343
344 const Router& router = item.second;
345
346 if (!router.adjacencyLsaString.empty()) {
347 std::cout << router.adjacencyLsaString << std::endl;
348 }
349
350 if (!router.coordinateLsaString.empty()) {
351 std::cout << router.coordinateLsaString << std::endl;
352 }
353
354 if (!router.nameLsaString.empty()) {
355 std::cout << router.nameLsaString << std::endl;
356 }
357 }
358}
359
360Nlsrc::Router&
361Nlsrc::getRouter(const nlsr::tlv::LsaInfo& info)
362{
363 const ndn::Name& originRouterName = info.getOriginRouter();
364
365 const auto& pair =
Alexander Afanasyevf9f39102015-12-01 17:43:40 -0800366 m_routers.insert(std::make_pair(originRouterName, Router()));
Vince Lehmanc439d662015-04-27 10:56:00 -0500367
368 return pair.first->second;
369}
370
371} // namespace nlsrc
372
373////////////////////////////////////////////////////////////////////////////////
374////////////////////////////////////////////////////////////////////////////////
375
376int
377main(int argc, char** argv)
378{
379 ndn::Face face;
380 nlsrc::Nlsrc nlsrc(face);
381
382 nlsrc.programName = argv[0];
383
384 if (argc < 2) {
385 nlsrc.printUsage();
386 return 0;
387 }
388
389 int opt;
390 while ((opt = ::getopt(argc, argv, "hV")) != -1) {
391 switch (opt) {
392 case 'h':
393 nlsrc.printUsage();
394 return 0;
395 case 'V':
396 std::cout << NLSR_VERSION_BUILD_STRING << std::endl;
397 return 0;
398 default:
399 nlsrc.printUsage();
400 return 1;
401 }
402 }
403
404 if (argc == ::optind) {
405 nlsrc.printUsage();
406 return 1;
407 }
408
409 try {
410 ::optind = 2; // Set ::optind to the command's index
411
412 nlsrc.commandLineArguments = argv + ::optind;
413 nlsrc.nOptions = argc - ::optind;
414
415 // argv[1] points to the command, so pass it to the dispatch
416 bool isOk = nlsrc.dispatch(argv[1]);
417 if (!isOk) {
418 nlsrc.printUsage();
419 return 1;
420 }
421
422 face.processEvents();
423 }
424 catch (const std::exception& e) {
425 std::cerr << "ERROR: " << e.what() << std::endl;
426 return 2;
427 }
428 return 0;
Alexander Afanasyevf9f39102015-12-01 17:43:40 -0800429}