blob: 9eeed3ae4ae3a1ceee1414810e587bb2ce030eee [file] [log] [blame]
Vince Lehmanc439d662015-04-27 10:56:00 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Ashlesh Gawande0421bc62020-05-08 20:42:19 -07002/*
Junxiao Shia3a63972022-01-24 02:03:41 +00003 * Copyright (c) 2014-2022, 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/>.
Ashlesh Gawande0421bc62020-05-08 20:42:19 -070020 */
Vince Lehmanc439d662015-04-27 10:56:00 -050021
22#include "nlsrc.hpp"
23
Junxiao Shia3a63972022-01-24 02:03:41 +000024#include "config.hpp"
Vince Lehmanc439d662015-04-27 10:56:00 -050025#include "version.hpp"
laqinfan35731852017-08-08 06:17:39 -050026#include "src/publisher/dataset-interest-handler.hpp"
Vince Lehmanc439d662015-04-27 10:56:00 -050027
Vince Lehmanc439d662015-04-27 10:56:00 -050028#include <ndn-cxx/data.hpp>
Vince Lehmanc439d662015-04-27 10:56:00 -050029#include <ndn-cxx/encoding/block.hpp>
Ashlesh Gawande30d96e42021-03-21 19:15:33 -070030#include <ndn-cxx/face.hpp>
31#include <ndn-cxx/interest.hpp>
Junxiao Shi3e5120c2016-09-10 16:58:34 +000032#include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
33#include <ndn-cxx/mgmt/nfd/control-response.hpp>
Davide Pesavento6184c202021-05-17 02:28:03 -040034#include <ndn-cxx/security/interest-signer.hpp>
Ashlesh Gawande30d96e42021-03-21 19:15:33 -070035#include <ndn-cxx/security/key-chain.hpp>
36#include <ndn-cxx/security/signing-helpers.hpp>
Junxiao Shia3a63972022-01-24 02:03:41 +000037#include <ndn-cxx/security/validator-config.hpp>
38#include <ndn-cxx/security/validator-null.hpp>
Ashlesh Gawande30d96e42021-03-21 19:15:33 -070039#include <ndn-cxx/util/segment-fetcher.hpp>
Vince Lehmanc439d662015-04-27 10:56:00 -050040
Junxiao Shia3a63972022-01-24 02:03:41 +000041#include <boost/algorithm/string/replace.hpp>
42#include <boost/property_tree/info_parser.hpp>
43
Vince Lehmanc439d662015-04-27 10:56:00 -050044#include <iostream>
45
46namespace nlsrc {
47
Junxiao Shia3a63972022-01-24 02:03:41 +000048const ndn::Name LOCALHOST_PREFIX("/localhost");
49const ndn::PartialName LSDB_SUFFIX("nlsr/lsdb");
50const ndn::PartialName NAME_UPDATE_SUFFIX("nlsr/prefix-update");
51const ndn::PartialName RT_SUFFIX("nlsr/routing-table");
Vince Lehmanc439d662015-04-27 10:56:00 -050052
Junxiao Shia3a63972022-01-24 02:03:41 +000053const uint32_t ERROR_CODE_TIMEOUT = 10060;
54const uint32_t RESPONSE_CODE_SUCCESS = 200;
55const uint32_t RESPONSE_CODE_SAVE_OR_DELETE = 205;
laqinfan35731852017-08-08 06:17:39 -050056
Junxiao Shia3a63972022-01-24 02:03:41 +000057Nlsrc::Nlsrc(std::string programName, ndn::Face& face)
58 : m_programName(std::move(programName))
59 , m_routerPrefix(LOCALHOST_PREFIX)
60 , m_face(face)
Vince Lehmanc439d662015-04-27 10:56:00 -050061{
Junxiao Shia3a63972022-01-24 02:03:41 +000062 disableValidator();
Vince Lehmanc439d662015-04-27 10:56:00 -050063}
64
65void
Junxiao Shia3a63972022-01-24 02:03:41 +000066Nlsrc::printUsage() const
Vince Lehmanc439d662015-04-27 10:56:00 -050067{
Junxiao Shia3a63972022-01-24 02:03:41 +000068 std::string help(R"EOT(Usage:
69@NLSRC@ [-h | -V]
70@NLSRC@ [-R <router prefix> [-c <nlsr.conf path> | -k]] COMMAND [<Command Options>]
71 -h print usage and exit
72 -V print version and exit
73 -R target a remote NLSR instance
74 -c verify response with nlsr.conf security.validator policy
75 -k do not verify response (insecure)
76
77 COMMAND can be one of the following:
78 lsdb
79 display NLSR lsdb status
80 routing
81 display routing table status
82 status
83 display all NLSR status (lsdb & routingtable)
84 advertise <name>
85 advertise a name prefix through NLSR
86 advertise <name> save
87 advertise and save the name prefix to the conf file
88 withdraw <name>
89 remove a name prefix advertised through NLSR
90 withdraw <name> delete
91 withdraw and delete the name prefix from the conf file
92)EOT");
93 boost::algorithm::replace_all(help, "@NLSRC@", m_programName);
94 std::cout << help;
95}
96
97void
98Nlsrc::setRouterPrefix(ndn::Name prefix)
99{
100 m_routerPrefix = std::move(prefix);
101}
102
103void
104Nlsrc::disableValidator()
105{
106 m_validator.reset(new ndn::security::ValidatorNull());
107}
108
109bool
110Nlsrc::enableValidator(const std::string& filename)
111{
112 using namespace boost::property_tree;
113 ptree validatorConfig;
114 try {
115 ptree config;
116 read_info(filename, config);
117 validatorConfig = config.get_child("security.validator");
118 }
119 catch (const ptree_error& e) {
120 std::cerr << "Failed to parse configuration file '" << filename
121 << "': " << e.what() << std::endl;
122 return false;
123 }
124
125 auto validator = std::make_unique<ndn::security::ValidatorConfig>(m_face);
126 try {
127 validator->load(validatorConfig, filename);
128 }
129 catch (const ndn::security::validator_config::Error& e) {
130 std::cerr << "Failed to load validator config from '" << filename
131 << "' security.validator section: " << e.what() << std::endl;
132 return false;
133 }
134
135 m_validator = std::move(validator);
136 return true;
Vince Lehmanc439d662015-04-27 10:56:00 -0500137}
138
139void
laqinfan35731852017-08-08 06:17:39 -0500140Nlsrc::getStatus(const std::string& command)
Vince Lehmanc439d662015-04-27 10:56:00 -0500141{
laqinfan35731852017-08-08 06:17:39 -0500142 if (command == "lsdb") {
143 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchAdjacencyLsas, this));
144 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchCoordinateLsas, this));
145 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchNameLsas, this));
146 m_fetchSteps.push_back(std::bind(&Nlsrc::printLsdb, this));
147 }
148 else if (command == "routing") {
149 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchRtables, this));
150 m_fetchSteps.push_back(std::bind(&Nlsrc::printRT, this));
151 }
Junxiao Shia3a63972022-01-24 02:03:41 +0000152 else if (command == "status") {
laqinfan35731852017-08-08 06:17:39 -0500153 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchAdjacencyLsas, this));
154 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchCoordinateLsas, this));
155 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchNameLsas, this));
156 m_fetchSteps.push_back(std::bind(&Nlsrc::fetchRtables, this));
157 m_fetchSteps.push_back(std::bind(&Nlsrc::printAll, this));
158 }
Vince Lehmanc439d662015-04-27 10:56:00 -0500159 runNextStep();
160}
161
162bool
Junxiao Shia3a63972022-01-24 02:03:41 +0000163Nlsrc::dispatch(ndn::span<std::string> subcommand)
Vince Lehmanc439d662015-04-27 10:56:00 -0500164{
Junxiao Shia3a63972022-01-24 02:03:41 +0000165 if (subcommand.size() == 0) {
166 return false;
Vince Lehmanc439d662015-04-27 10:56:00 -0500167 }
168
Junxiao Shia3a63972022-01-24 02:03:41 +0000169 if (subcommand[0] == "advertise") {
170 switch (subcommand.size()) {
171 case 2:
172 advertiseName(subcommand[1], false);
173 return true;
174 case 3:
175 if (subcommand[2] != "save") {
176 return false;
177 }
178 advertiseName(subcommand[1], true);
179 return true;
180 }
181 return false;
182 }
183
184 if (subcommand[0] == "withdraw") {
185 switch (subcommand.size()) {
186 case 2:
187 withdrawName(subcommand[1], false);
188 return true;
189 case 3:
190 if (subcommand[2] != "delete") {
191 return false;
192 }
193 withdrawName(subcommand[1], true);
194 return true;
195 }
196 return false;
197 }
198
199 if (subcommand[0] == "lsdb" || subcommand[0] == "routing" || subcommand[0] == "status") {
200 if (subcommand.size() != 1) {
201 return false;
202 }
203 getStatus(subcommand[0]);
204 return true;
205 }
Vince Lehmanc439d662015-04-27 10:56:00 -0500206 return false;
207}
208
209void
210Nlsrc::runNextStep()
211{
212 if (m_fetchSteps.empty()) {
213 return;
214 }
215
216 std::function<void()> nextStep = m_fetchSteps.front();
217 m_fetchSteps.pop_front();
218
219 nextStep();
220}
221
222void
Junxiao Shia3a63972022-01-24 02:03:41 +0000223Nlsrc::advertiseName(ndn::Name name, bool wantSave)
Vince Lehmanc439d662015-04-27 10:56:00 -0500224{
Junxiao Shia3a63972022-01-24 02:03:41 +0000225 std::string info = (wantSave ? "(Save: " : "(Advertise: ") + name.toUri() + ")";
Saurab Dulal7526cee2018-01-31 18:14:10 +0000226 ndn::Name::Component verb("advertise");
Junxiao Shia3a63972022-01-24 02:03:41 +0000227 sendNamePrefixUpdate(name, verb, info, wantSave);
Vince Lehmanc439d662015-04-27 10:56:00 -0500228}
229
230void
Junxiao Shia3a63972022-01-24 02:03:41 +0000231Nlsrc::withdrawName(ndn::Name name, bool wantDelete)
Vince Lehmanc439d662015-04-27 10:56:00 -0500232{
Junxiao Shia3a63972022-01-24 02:03:41 +0000233 std::string info = (wantDelete ? "(Delete: " : "(Withdraw: ") + name.toUri() + ")";
Saurab Dulal7526cee2018-01-31 18:14:10 +0000234 ndn::Name::Component verb("withdraw");
Junxiao Shia3a63972022-01-24 02:03:41 +0000235 sendNamePrefixUpdate(name, verb, info, wantDelete);
Vince Lehmanc439d662015-04-27 10:56:00 -0500236}
237
238void
239Nlsrc::sendNamePrefixUpdate(const ndn::Name& name,
240 const ndn::Name::Component& verb,
Saurab Dulal7526cee2018-01-31 18:14:10 +0000241 const std::string& info,
242 bool flag)
Vince Lehmanc439d662015-04-27 10:56:00 -0500243{
244 ndn::nfd::ControlParameters parameters;
245 parameters.setName(name);
Saurab Dulal7526cee2018-01-31 18:14:10 +0000246 if (flag) {
247 parameters.setFlags(1);
248 }
Vince Lehmanc439d662015-04-27 10:56:00 -0500249
Junxiao Shia3a63972022-01-24 02:03:41 +0000250 auto paramWire = parameters.wireEncode();
251 ndn::Name commandName = m_routerPrefix;
252 commandName.append(NAME_UPDATE_SUFFIX);
Vince Lehmanc439d662015-04-27 10:56:00 -0500253 commandName.append(verb);
Junxiao Shia3a63972022-01-24 02:03:41 +0000254 commandName.append(paramWire.begin(), paramWire.end());
Vince Lehmanc439d662015-04-27 10:56:00 -0500255
Davide Pesavento6184c202021-05-17 02:28:03 -0400256 ndn::security::InterestSigner signer(m_keyChain);
257 auto commandInterest = signer.makeCommandInterest(commandName,
258 ndn::security::signingByIdentity(m_keyChain.getPib().getDefaultIdentity()));
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -0500259 commandInterest.setMustBeFresh(true);
260
261 m_face.expressInterest(commandInterest,
Vince Lehmanc439d662015-04-27 10:56:00 -0500262 std::bind(&Nlsrc::onControlResponse, this, info, _2),
Alexander Afanasyev1de901f2017-03-09 12:43:57 -0800263 std::bind(&Nlsrc::onTimeout, this, ERROR_CODE_TIMEOUT, "Nack"),
Vince Lehmanc439d662015-04-27 10:56:00 -0500264 std::bind(&Nlsrc::onTimeout, this, ERROR_CODE_TIMEOUT, "Timeout"));
265}
266
267void
268Nlsrc::onControlResponse(const std::string& info, const ndn::Data& data)
269{
Vince Lehmand33e5bc2015-06-22 15:27:50 -0500270 if (data.getMetaInfo().getType() == ndn::tlv::ContentType_Nack) {
271 std::cerr << "ERROR: Run-time advertise/withdraw disabled" << std::endl;
272 return;
273 }
274
Vince Lehmanc439d662015-04-27 10:56:00 -0500275 ndn::nfd::ControlResponse response;
276
277 try {
278 response.wireDecode(data.getContent().blockFromValue());
279 }
280 catch (const std::exception& e) {
281 std::cerr << "ERROR: Control response decoding error" << std::endl;
282 return;
283 }
284
285 uint32_t code = response.getCode();
286
Saurab Dulal7526cee2018-01-31 18:14:10 +0000287 if (code != RESPONSE_CODE_SUCCESS && code != RESPONSE_CODE_SAVE_OR_DELETE) {
288
289 std::cerr << response.getText() << std::endl;
Vince Lehmanc439d662015-04-27 10:56:00 -0500290 std::cerr << "Name prefix update error (code: " << code << ")" << std::endl;
291 return;
292 }
293
294 std::cout << "Applied Name prefix update successfully: " << info << std::endl;
295}
296
297void
298Nlsrc::fetchAdjacencyLsas()
299{
Ashlesh Gawande0db4d4d2020-02-05 20:30:02 -0800300 fetchFromLsdb<nlsr::AdjLsa>(nlsr::dataset::ADJACENCY_COMPONENT,
301 std::bind(&Nlsrc::recordLsa, this, _1));
Vince Lehmanc439d662015-04-27 10:56:00 -0500302}
303
304void
305Nlsrc::fetchCoordinateLsas()
306{
Ashlesh Gawande0db4d4d2020-02-05 20:30:02 -0800307 fetchFromLsdb<nlsr::CoordinateLsa>(nlsr::dataset::COORDINATE_COMPONENT,
308 std::bind(&Nlsrc::recordLsa, this, _1));
Vince Lehmanc439d662015-04-27 10:56:00 -0500309}
310
311void
312Nlsrc::fetchNameLsas()
313{
Ashlesh Gawande0db4d4d2020-02-05 20:30:02 -0800314 fetchFromLsdb<nlsr::NameLsa>(nlsr::dataset::NAME_COMPONENT,
315 std::bind(&Nlsrc::recordLsa, this, _1));
Vince Lehmanc439d662015-04-27 10:56:00 -0500316}
317
laqinfan35731852017-08-08 06:17:39 -0500318void
319Nlsrc::fetchRtables()
320{
Ashlesh Gawande0af46272020-12-12 16:45:13 -0500321 fetchFromRt<nlsr::RoutingTableStatus>([this] (const auto& rts) { this->recordRtable(rts); });
laqinfan35731852017-08-08 06:17:39 -0500322}
323
Junxiao Shia3a63972022-01-24 02:03:41 +0000324template<class T>
Vince Lehmanc439d662015-04-27 10:56:00 -0500325void
326Nlsrc::fetchFromLsdb(const ndn::Name::Component& datasetType,
327 const std::function<void(const T&)>& recordLsa)
328{
Junxiao Shia3a63972022-01-24 02:03:41 +0000329 auto name = m_routerPrefix;
330 name.append(LSDB_SUFFIX);
331 name.append(datasetType);
332 ndn::Interest interest(name);
Vince Lehmanc439d662015-04-27 10:56:00 -0500333
Junxiao Shia3a63972022-01-24 02:03:41 +0000334 auto fetcher = ndn::util::SegmentFetcher::start(m_face, interest, *m_validator);
Ashlesh Gawande05cb7282018-08-30 14:39:41 -0500335 fetcher->onComplete.connect(std::bind(&Nlsrc::onFetchSuccess<T>, this, _1, recordLsa));
336 fetcher->onError.connect(std::bind(&Nlsrc::onTimeout, this, _1, _2));
Vince Lehmanc439d662015-04-27 10:56:00 -0500337}
338
Ashlesh Gawande57a87172020-05-09 19:47:06 -0700339void
340Nlsrc::recordLsa(const nlsr::Lsa& lsa)
341{
342 Router& router = m_routers.emplace(lsa.getOriginRouter(), Router()).first->second;
343
344 if (lsa.getType() == nlsr::Lsa::Type::ADJACENCY) {
345 router.adjacencyLsaString = lsa.toString();
346 }
347 else if (lsa.getType() == nlsr::Lsa::Type::COORDINATE) {
348 router.coordinateLsaString = lsa.toString();
349 }
350 else if (lsa.getType() == nlsr::Lsa::Type::NAME) {
351 router.nameLsaString = lsa.toString();
352 }
353}
354
Junxiao Shia3a63972022-01-24 02:03:41 +0000355template<class T>
Vince Lehmanc439d662015-04-27 10:56:00 -0500356void
laqinfan35731852017-08-08 06:17:39 -0500357Nlsrc::fetchFromRt(const std::function<void(const T&)>& recordDataset)
358{
Junxiao Shia3a63972022-01-24 02:03:41 +0000359 auto name = m_routerPrefix;
360 name.append(RT_SUFFIX);
361 ndn::Interest interest(name);
laqinfan35731852017-08-08 06:17:39 -0500362
Junxiao Shia3a63972022-01-24 02:03:41 +0000363 auto fetcher = ndn::util::SegmentFetcher::start(m_face, interest, *m_validator);
Ashlesh Gawande05cb7282018-08-30 14:39:41 -0500364 fetcher->onComplete.connect(std::bind(&Nlsrc::onFetchSuccess<T>, this, _1, recordDataset));
365 fetcher->onError.connect(std::bind(&Nlsrc::onTimeout, this, _1, _2));
laqinfan35731852017-08-08 06:17:39 -0500366}
367
Junxiao Shia3a63972022-01-24 02:03:41 +0000368template<class T>
laqinfan35731852017-08-08 06:17:39 -0500369void
Vince Lehmanc439d662015-04-27 10:56:00 -0500370Nlsrc::onFetchSuccess(const ndn::ConstBufferPtr& data,
laqinfan35731852017-08-08 06:17:39 -0500371 const std::function<void(const T&)>& recordDataset)
Vince Lehmanc439d662015-04-27 10:56:00 -0500372{
373 ndn::Block block;
374 size_t offset = 0;
375
376 while (offset < data->size()) {
377 bool isOk = false;
378 std::tie(isOk, block) = ndn::Block::fromBuffer(data, offset);
379
380 if (!isOk) {
381 std::cerr << "ERROR: cannot decode LSA TLV" << std::endl;
382 break;
383 }
384
385 offset += block.size();
386
laqinfan35731852017-08-08 06:17:39 -0500387 T data(block);
388 recordDataset(data);
Vince Lehmanc439d662015-04-27 10:56:00 -0500389 }
390
391 runNextStep();
392}
393
394void
395Nlsrc::onTimeout(uint32_t errorCode, const std::string& error)
396{
397 std::cerr << "Request timed out (code: " << errorCode
398 << ", error: " << error << ")" << std::endl;
399}
400
Vince Lehmanc439d662015-04-27 10:56:00 -0500401void
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700402Nlsrc::recordRtable(const nlsr::RoutingTableStatus& rts)
laqinfan35731852017-08-08 06:17:39 -0500403{
laqinfan35731852017-08-08 06:17:39 -0500404 std::ostringstream os;
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700405 os << rts;
laqinfana073e2e2018-01-15 21:17:24 +0000406 m_rtString = os.str();
laqinfan35731852017-08-08 06:17:39 -0500407}
408
409void
Vince Lehmanc439d662015-04-27 10:56:00 -0500410Nlsrc::printLsdb()
411{
Vince Lehmanc439d662015-04-27 10:56:00 -0500412 std::cout << "LSDB:" << std::endl;
413
414 for (const auto& item : m_routers) {
415 std::cout << " OriginRouter: " << item.first << std::endl;
416 std::cout << std::endl;
417
418 const Router& router = item.second;
419
420 if (!router.adjacencyLsaString.empty()) {
421 std::cout << router.adjacencyLsaString << std::endl;
422 }
423
424 if (!router.coordinateLsaString.empty()) {
425 std::cout << router.coordinateLsaString << std::endl;
426 }
427
428 if (!router.nameLsaString.empty()) {
429 std::cout << router.nameLsaString << std::endl;
430 }
431 }
432}
433
laqinfan35731852017-08-08 06:17:39 -0500434void
435Nlsrc::printRT()
436{
laqinfana073e2e2018-01-15 21:17:24 +0000437 if (!m_rtString.empty()) {
Ashlesh Gawande0421bc62020-05-08 20:42:19 -0700438 std::cout << m_rtString;
laqinfana073e2e2018-01-15 21:17:24 +0000439 }
440 else {
441 std::cout << "Routing Table is not calculated yet" << std::endl;
laqinfan35731852017-08-08 06:17:39 -0500442 }
443}
444
445void
446Nlsrc::printAll()
447{
448 std::cout << "NLSR Status" << std::endl;
449 printLsdb();
450 printRT();
451}
452
Vince Lehmanc439d662015-04-27 10:56:00 -0500453} // namespace nlsrc
454
455////////////////////////////////////////////////////////////////////////////////
456////////////////////////////////////////////////////////////////////////////////
457
458int
459main(int argc, char** argv)
460{
461 ndn::Face face;
Junxiao Shia3a63972022-01-24 02:03:41 +0000462 nlsrc::Nlsrc nlsrc(argv[0], face);
Vince Lehmanc439d662015-04-27 10:56:00 -0500463
464 if (argc < 2) {
465 nlsrc.printUsage();
466 return 0;
467 }
468
469 int opt;
Junxiao Shia3a63972022-01-24 02:03:41 +0000470 const char* confFile = DEFAULT_CONFIG_FILE;
471 bool disableValidator = false;
472 while ((opt = ::getopt(argc, argv, "hVR:c:k")) != -1) {
Vince Lehmanc439d662015-04-27 10:56:00 -0500473 switch (opt) {
474 case 'h':
475 nlsrc.printUsage();
476 return 0;
477 case 'V':
478 std::cout << NLSR_VERSION_BUILD_STRING << std::endl;
479 return 0;
Junxiao Shia3a63972022-01-24 02:03:41 +0000480 case 'R':
481 nlsrc.setRouterPrefix(::optarg);
482 break;
483 case 'c':
484 confFile = ::optarg;
485 break;
486 case 'k':
487 disableValidator = true;
488 break;
Vince Lehmanc439d662015-04-27 10:56:00 -0500489 default:
490 nlsrc.printUsage();
491 return 1;
492 }
493 }
494
495 if (argc == ::optind) {
496 nlsrc.printUsage();
497 return 1;
498 }
499
Junxiao Shia3a63972022-01-24 02:03:41 +0000500 if (nlsrc.getRouterPrefix() != nlsrc::LOCALHOST_PREFIX && !disableValidator) {
501 if (!nlsrc.enableValidator(confFile)) {
502 return 1;
503 }
504 }
505
506 std::vector<std::string> subcommand;
507 std::copy(&argv[::optind], &argv[argc], std::back_inserter(subcommand));
508
Vince Lehmanc439d662015-04-27 10:56:00 -0500509 try {
Junxiao Shia3a63972022-01-24 02:03:41 +0000510 bool isOk = nlsrc.dispatch(subcommand);
Vince Lehmanc439d662015-04-27 10:56:00 -0500511 if (!isOk) {
512 nlsrc.printUsage();
513 return 1;
514 }
515
516 face.processEvents();
517 }
518 catch (const std::exception& e) {
519 std::cerr << "ERROR: " << e.what() << std::endl;
520 return 2;
521 }
522 return 0;
Alexander Afanasyevf9f39102015-12-01 17:43:40 -0800523}