27#include <ndn-cxx/name.hpp>
28#include <ndn-cxx/net/face-uri.hpp>
29#include <ndn-cxx/util/io.hpp>
31#include <boost/algorithm/string.hpp>
32#include <boost/property_tree/info_parser.hpp>
33#include <boost/property_tree/exceptions.hpp>
41namespace fs = std::filesystem;
44class ConfigurationVariable
47 typedef std::function<void(T)> ConfParameterCallback;
49 ConfigurationVariable(
const std::string& key,
const ConfParameterCallback& setter)
51 , m_setterCallback(setter)
54 , m_shouldCheckRange(false)
63 T value = section.get<T>(m_key);
65 if (!isValidValue(value)) {
69 m_setterCallback(value);
72 catch (
const std::exception& ex) {
75 std::cerr << ex.what() << std::endl;
76 std::cerr <<
"Missing required configuration variable" << std::endl;
80 m_setterCallback(m_defaultValue);
89 setMinAndMaxValue(T min, T max)
93 m_shouldCheckRange =
true;
97 setOptional(T defaultValue)
100 m_defaultValue = defaultValue;
105 printOutOfRangeError(T value)
107 std::cerr <<
"Invalid value for " << m_key <<
": "
110 << m_minValue <<
" - "
111 << m_maxValue << std::endl;
115 isValidValue(T value)
117 if (!m_shouldCheckRange) {
120 else if (value < m_minValue || value > m_maxValue)
122 printOutOfRangeError(value);
130 const std::string m_key;
131 const ConfParameterCallback m_setterCallback;
137 bool m_shouldCheckRange;
142 : m_confFileName(confParam.getConfFileName())
143 , m_confParam(confParam)
150 std::ifstream inputFile(m_confFileName);
151 if (!inputFile.is_open()) {
152 std::cerr <<
"Failed to read configuration file: " << m_confFileName << std::endl;
156 if (!load(inputFile)) {
166ConfFileProcessor::load(std::istream& input)
170 boost::property_tree::read_info(input, pt);
172 catch (
const boost::property_tree::ptree_error& e) {
173 std::cerr <<
"Failed to parse configuration file '" << m_confFileName
174 <<
"': " << e.what() << std::endl;
178 for (
const auto& tn : pt) {
179 if (!processSection(tn.first, tn.second)) {
187ConfFileProcessor::processSection(
const std::string& sectionName,
const ConfigSection& section)
190 if (sectionName ==
"general") {
191 ret = processConfSectionGeneral(section);
193 else if (sectionName ==
"neighbors") {
194 ret = processConfSectionNeighbors(section);
196 else if (sectionName ==
"hyperbolic") {
197 ret = processConfSectionHyperbolic(section);
199 else if (sectionName ==
"fib") {
200 ret = processConfSectionFib(section);
202 else if (sectionName ==
"advertising") {
203 ret = processConfSectionAdvertising(section);
205 else if (sectionName ==
"security") {
206 ret = processConfSectionSecurity(section);
209 std::cerr <<
"Unknown configuration section: " << sectionName << std::endl;
215ConfFileProcessor::processConfSectionGeneral(
const ConfigSection& section)
218 std::string syncProtocol = section.get<std::string>(
"sync-protocol",
"psync");
219 if (syncProtocol ==
"chronosync") {
220#ifdef HAVE_CHRONOSYNC
223 std::cerr <<
"NLSR was compiled without ChronoSync support!\n";
227 else if (syncProtocol ==
"psync") {
231 std::cerr <<
"NLSR was compiled without PSync support!\n";
235 else if (syncProtocol ==
"svs") {
239 std::cerr <<
"NLSR was compiled without SVS support!\n";
244 std::cerr <<
"Sync protocol '" << syncProtocol <<
"' is not supported!\n"
245 <<
"Use 'chronosync' or 'psync' or 'svs'\n";
250 std::string network = section.get<std::string>(
"network");
251 std::string site = section.get<std::string>(
"site");
252 std::string router = section.get<std::string>(
"router");
253 ndn::Name networkName(network);
254 if (!networkName.empty()) {
258 std::cerr <<
"Network can not be null or empty or in bad URI format" << std::endl;
261 ndn::Name siteName(site);
262 if (!siteName.empty()) {
266 std::cerr <<
"Site can not be null or empty or in bad URI format" << std::endl;
269 ndn::Name routerName(router);
270 if (!routerName.empty()) {
274 std::cerr <<
"Router name can not be null or empty or in bad URI format" << std::endl;
278 catch (
const std::exception& ex) {
279 std::cerr << ex.what() << std::endl;
290 std::cerr <<
"Invalid value for lsa-refresh-time. "
297 uint32_t routerDeadInterval = section.get<uint32_t>(
"router-dead-interval", 2 * lsaRefreshTime);
303 std::cerr <<
"Value of router-dead-interval must be larger than lsa-refresh-time" << std::endl;
314 std::cerr <<
"Invalid value for lsa-interest-timeout. "
321 uint32_t syncInterestLifetime = section.get<uint32_t>(
"sync-interest-lifetime",
328 std::cerr <<
"Invalid value for sync-interest-lifetime. "
336 fs::path stateDir(section.get<std::string>(
"state-dir"));
337 if (fs::exists(stateDir)) {
338 if (fs::is_directory(stateDir)) {
340 auto conFileDynamic = stateDir /
"nlsr.conf";
341 if (m_confFileName == conFileDynamic.string()) {
342 std::cerr <<
"Please use nlsr.conf stored at another location "
343 <<
"or change the state-dir in the configuration." << std::endl;
344 std::cerr <<
"The file at " << conFileDynamic <<
345 " is used as dynamic file for saving NLSR runtime changes." << std::endl;
346 std::cerr <<
"The dynamic file can be used for next run "
347 <<
"after copying to another location." << std::endl;
353 fs::copy_file(m_confFileName, conFileDynamic, fs::copy_options::overwrite_existing);
355 catch (
const fs::filesystem_error& e) {
356 std::cerr <<
"Error copying conf file to state-dir: " << e.what() << std::endl;
360 auto testFilePath = stateDir /
"test.seq";
361 std::ofstream testFile(testFilePath);
366 std::cerr <<
"NLSR does not have read/write permission on state-dir" << std::endl;
370 fs::remove(testFilePath);
373 std::cerr <<
"Provided state-dir " << stateDir <<
" is not a directory" << std::endl;
378 std::cerr <<
"Provided state-dir " << stateDir <<
" does not exist" << std::endl;
382 catch (
const std::exception& ex) {
383 std::cerr <<
"You must configure state-dir" << std::endl;
384 std::cerr << ex.what() << std::endl;
392ConfFileProcessor::processConfSectionNeighbors(
const ConfigSection& section)
401 std::cerr <<
"Invalid value for hello-retries. "
413 std::cerr <<
"Invalid value for hello-timeout. "
425 std::cerr <<
"Invalid value for hello-interval. "
432 ConfigurationVariable<uint32_t> adjLsaBuildInterval(
"adj-lsa-build-interval",
438 if (!adjLsaBuildInterval.parseFromConfigSection(section)) {
442 ConfigurationVariable<uint32_t> faceDatasetFetchTries(
"face-dataset-fetch-tries",
450 if (!faceDatasetFetchTries.parseFromConfigSection(section)) {
455 ConfigurationVariable<uint32_t> faceDatasetFetchInterval(
"face-dataset-fetch-interval",
463 if (!faceDatasetFetchInterval.parseFromConfigSection(section)) {
467 for (
const auto& tn : section) {
468 if (tn.first ==
"neighbor") {
471 std::string name = CommandAttriTree.get<std::string>(
"name");
472 std::string uriString = CommandAttriTree.get<std::string>(
"face-uri");
474 ndn::FaceUri faceUri;
475 if (!faceUri.parse(uriString)) {
476 std::cerr <<
"face-uri parsing failed" << std::endl;
480 bool failedToCanonize =
false;
481 faceUri.canonize([&faceUri] (
const auto& canonicalUri) {
482 faceUri = canonicalUri;
484 [&faceUri, &failedToCanonize] (
const auto& reason) {
485 failedToCanonize =
true;
486 std::cerr <<
"Could not canonize URI: '" << faceUri
487 <<
"' because: " << reason << std::endl;
494 if (failedToCanonize) {
499 ndn::Name neighborName(name);
500 if (!neighborName.empty()) {
505 std::cerr <<
"No neighbor name found or bad URI format! Expected:\n"
506 <<
" name [neighbor router name]\n face-uri [face uri]\n link-cost [link cost] OPTIONAL" << std::endl;
509 catch (
const std::exception& ex) {
510 std::cerr << ex.what() << std::endl;
519ConfFileProcessor::processConfSectionHyperbolic(
const ConfigSection& section)
522 std::string state = section.get<std::string>(
"state",
"off");
524 if (boost::iequals(state,
"off")) {
527 else if (boost::iequals(state,
"on")) {
530 else if (boost::iequals(state,
"dry-run")) {
534 std::cerr <<
"Invalid setting for hyperbolic state. "
535 <<
"Allowed values: off, on, dry-run" << std::endl;
544 double radius = section.get<
double>(
"radius");
545 std::string angleString = section.get<std::string>(
"angle");
547 std::stringstream ss(angleString);
548 std::vector<double> angles;
552 while (ss >> angle) {
553 angles.push_back(angle);
554 if (ss.peek() ==
',' || ss.peek() ==
' ') {
559 if (!m_confParam.
setCorR(radius)) {
564 catch (
const std::exception& ex) {
565 std::cerr << ex.what() << std::endl;
566 if (state ==
"on" || state ==
"dry-run") {
575ConfFileProcessor::processConfSectionFib(
const ConfigSection& section)
585 std::cerr <<
"Invalid value for max-faces-per-prefix. "
592 ConfigurationVariable<uint32_t> routingCalcInterval(
"routing-calc-interval",
598 if (!routingCalcInterval.parseFromConfigSection(section)) {
606ConfFileProcessor::processConfSectionAdvertising(
const ConfigSection& section)
608 for (
const auto& tn : section) {
610 ndn::Name namePrefix(tn.first.data());
611 if (!namePrefix.empty()) {
615 std::cerr <<
" Wrong format or bad URI!\nExpected [name in ndn URI format] [cost],"
616 <<
" got prefix: " << tn.first.data() <<
" cost:" << tn.second.data() << std::endl;
620 catch (
const boost::property_tree::ptree_bad_data& ex) {
622 std::cerr <<
"Invalid cost format; only integers are allowed" << std::endl;
625 catch (
const std::exception& ex) {
626 std::cerr << ex.what() << std::endl;
634ConfFileProcessor::processConfSectionSecurity(
const ConfigSection& section)
636 auto it = section.begin();
638 if (it == section.end() || it->first !=
"validator") {
639 std::cerr <<
"Error: Expected validator section!" << std::endl;
643 m_confParam.
getValidator().load(it->second, m_confFileName);
646 if (it != section.end() && it->first ==
"prefix-update-validator") {
650 for (; it != section.end(); it++) {
651 if (it->first !=
"cert-to-publish") {
652 std::cerr <<
"Error: Expected cert-to-publish!" << std::endl;
656 fs::path certPath = fs::canonical(fs::path(m_confFileName).parent_path() / it->second.data());
657 std::ifstream ifs(certPath);
659 ndn::security::Certificate idCert;
661 idCert = ndn::io::loadTlv<ndn::security::Certificate>(ifs);
663 catch (
const std::exception& e) {
664 std::cerr <<
"Error: Cannot load cert-to-publish " << certPath <<
": " << e.what() << std::endl;
bool insert(const Adjacent &adjacent)
static constexpr double DEFAULT_LINK_COST
ConfFileProcessor(ConfParameter &confParam)
bool processConfFile()
Load and parse the configuration file, then populate NLSR.
A class to house all the configuration parameters for NLSR.
void setHyperbolicState(HyperbolicState ihc)
void setRouterName(const ndn::Name &routerName)
void setSiteName(const ndn::Name &siteName)
void setInterestRetryNumber(uint32_t irn)
void setMaxFacesPerPrefix(uint32_t mfpp)
void setRouterDeadInterval(uint32_t rdt)
void writeLog()
Dump the current state of all attributes to the log.
void setSyncProtocol(SyncProtocol syncProtocol)
void setStateFileDir(const std::string &ssfd)
void setLsaRefreshTime(uint32_t lrt)
void setInterestResendTime(uint32_t irt)
void loadCertToValidator(const ndn::security::Certificate &cert)
uint32_t getLsaRefreshTime() const
NamePrefixList & getNamePrefixList()
void setAdjLsaBuildInterval(uint32_t interval)
void setConfFileNameDynamic(const std::string &confFileDynamic)
void setInfoInterestInterval(uint32_t iii)
void addCertPath(const std::string &certPath)
void setFaceDatasetFetchTries(uint32_t count)
void setLsaInterestLifetime(const ndn::time::seconds &lifetime)
void setSyncInterestLifetime(uint32_t syncInterestLifetime)
void setCorTheta(const std::vector< double > &ct)
void setFaceDatasetFetchInterval(uint32_t interval)
AdjacencyList & getAdjacencyList()
ndn::security::ValidatorConfig & getPrefixUpdateValidator()
void setNetwork(const ndn::Name &networkName)
void buildRouterAndSyncUserPrefix()
ndn::security::ValidatorConfig & getValidator()
void setRoutingCalcInterval(uint32_t interval)
bool insert(const ndn::Name &name, const std::string &source="", double cost=0)
Inserts name and source combination.
Copyright (c) 2014-2020, The University of Memphis, Regents of the University of California.
@ FACE_DATASET_FETCH_TRIES_DEFAULT
@ FACE_DATASET_FETCH_TRIES_MIN
@ FACE_DATASET_FETCH_TRIES_MAX
@ LSA_REFRESH_TIME_DEFAULT
@ ROUTING_CALC_INTERVAL_DEFAULT
@ ROUTING_CALC_INTERVAL_MIN
@ ROUTING_CALC_INTERVAL_MAX
@ MAX_FACES_PER_PREFIX_MIN
@ MAX_FACES_PER_PREFIX_DEFAULT
@ MAX_FACES_PER_PREFIX_MAX
@ FACE_DATASET_FETCH_INTERVAL_DEFAULT
@ FACE_DATASET_FETCH_INTERVAL_MIN
@ FACE_DATASET_FETCH_INTERVAL_MAX
constexpr ndn::time::seconds TIME_ALLOWED_FOR_CANONIZATION
@ ADJ_LSA_BUILD_INTERVAL_DEFAULT
@ ADJ_LSA_BUILD_INTERVAL_MIN
@ ADJ_LSA_BUILD_INTERVAL_MAX
@ HYPERBOLIC_STATE_DRY_RUN
@ LSA_INTEREST_LIFETIME_MAX
@ LSA_INTEREST_LIFETIME_DEFAULT
@ LSA_INTEREST_LIFETIME_MIN
boost::property_tree::ptree ConfigSection
@ SYNC_INTEREST_LIFETIME_MIN
@ SYNC_INTEREST_LIFETIME_MAX
@ SYNC_INTEREST_LIFETIME_DEFAULT