conf-file-processor.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
22 #include "conf-file-processor.hpp"
23 #include "conf-parameter.hpp"
24 #include "adjacent.hpp"
25 #include "utility/name-helper.hpp"
27 
28 #include <boost/cstdint.hpp>
29 
30 #include <ndn-cxx/name.hpp>
31 #include <ndn-cxx/net/face-uri.hpp>
32 
33 #include <iostream>
34 #include <fstream>
35 
36 namespace nlsr {
37 
38 template <class T>
40 {
41 public:
42  typedef std::function<void(T)> ConfParameterCallback;
43  typedef boost::property_tree::ptree ConfigSection;
44 
45  ConfigurationVariable(const std::string& key, const ConfParameterCallback& setter)
46  : m_key(key)
47  , m_setterCallback(setter)
48  , m_minValue(0)
49  , m_maxValue(0)
50  , m_shouldCheckRange(false)
51  , m_isRequired(true)
52  {
53  }
54 
55  bool
56  parseFromConfigSection(const ConfigSection& section)
57  {
58  try {
59  T value = section.get<T>(m_key);
60 
61  if (!isValidValue(value)) {
62  return false;
63  }
64 
65  m_setterCallback(value);
66  return true;
67  }
68  catch (const std::exception& ex) {
69 
70  if (m_isRequired) {
71  std::cerr << ex.what() << std::endl;
72  std::cerr << "Missing required configuration variable" << std::endl;
73  return false;
74  }
75  else {
76  m_setterCallback(m_defaultValue);
77  return true;
78  }
79  }
80 
81  return false;
82  }
83 
84  void
85  setMinAndMaxValue(T min, T max)
86  {
87  m_minValue = min;
88  m_maxValue = max;
89  m_shouldCheckRange = true;
90  }
91 
92  void
93  setOptional(T defaultValue)
94  {
95  m_isRequired = false;
96  m_defaultValue = defaultValue;
97  }
98 
99 private:
100  void
101  printOutOfRangeError(T value)
102  {
103  std::cerr << "Invalid value for " << m_key << ": "
104  << value << ". "
105  << "Valid values: "
106  << m_minValue << " - "
107  << m_maxValue << std::endl;
108  }
109 
110  bool
111  isValidValue(T value)
112  {
113  if (!m_shouldCheckRange) {
114  return true;
115  }
116  else if (value < m_minValue || value > m_maxValue)
117  {
118  printOutOfRangeError(value);
119  return false;
120  }
121 
122  return true;
123  }
124 
125 private:
126  const std::string m_key;
127  const ConfParameterCallback m_setterCallback;
128  T m_defaultValue;
129 
130  T m_minValue;
131  T m_maxValue;
132 
133  bool m_shouldCheckRange;
134  bool m_isRequired;
135 };
136 
137 bool
139 {
140  bool ret = true;
141  std::ifstream inputFile;
142  inputFile.open(m_confFileName.c_str());
143  if (!inputFile.is_open()) {
144  std::string msg = "Failed to read configuration file: ";
145  msg += m_confFileName;
146  std::cerr << msg << std::endl;
147  return false;
148  }
149  ret = load(inputFile);
150  inputFile.close();
151  return ret;
152 }
153 
154 bool
155 ConfFileProcessor::load(std::istream& input)
156 {
157  ConfigSection pt;
158  bool ret = true;
159  try {
160  boost::property_tree::read_info(input, pt);
161  }
162  catch (const boost::property_tree::info_parser_error& error) {
163  std::stringstream msg;
164  std::cerr << "Failed to parse configuration file " << std::endl;
165  std::cerr << m_confFileName << std::endl;
166  return false;
167  }
168 
169  for (ConfigSection::const_iterator tn = pt.begin();
170  tn != pt.end(); ++tn) {
171  ret = processSection(tn->first, tn->second);
172  if (ret == false) {
173  break;
174  }
175  }
176  return ret;
177 }
178 
179 bool
180 ConfFileProcessor::processSection(const std::string& sectionName, const ConfigSection& section)
181 {
182  bool ret = true;
183  if (sectionName == "general")
184  {
185  ret = processConfSectionGeneral(section);
186  }
187  else if (sectionName == "neighbors")
188  {
189  ret = processConfSectionNeighbors(section);
190  }
191  else if (sectionName == "hyperbolic")
192  {
193  ret = processConfSectionHyperbolic(section);
194  }
195  else if (sectionName == "fib")
196  {
197  ret = processConfSectionFib(section);
198  }
199  else if (sectionName == "advertising")
200  {
201  ret = processConfSectionAdvertising(section);
202  }
203  else if (sectionName == "security")
204  {
205  ret = processConfSectionSecurity(section);
206  }
207  else
208  {
209  std::cerr << "Wrong configuration section: " << sectionName << std::endl;
210  }
211  return ret;
212 }
213 
214 bool
215 ConfFileProcessor::processConfSectionGeneral(const ConfigSection& section)
216 {
217  try {
218  std::string network = section.get<std::string>("network");
219  std::string site = section.get<std::string>("site");
220  std::string router = section.get<std::string>("router");
221  ndn::Name networkName(network);
222  if (!networkName.empty()) {
223  m_nlsr.getConfParameter().setNetwork(networkName);
224  }
225  else {
226  std::cerr << " Network can not be null or empty or in bad URI format :(!" << std::endl;
227  return false;
228  }
229  ndn::Name siteName(site);
230  if (!siteName.empty()) {
231  m_nlsr.getConfParameter().setSiteName(siteName);
232  }
233  else {
234  std::cerr << "Site can not be null or empty or in bad URI format:( !" << std::endl;
235  return false;
236  }
237  ndn::Name routerName(router);
238  if (!routerName.empty()) {
239  m_nlsr.getConfParameter().setRouterName(routerName);
240  }
241  else {
242  std::cerr << " Router name can not be null or empty or in bad URI format:( !" << std::endl;
243  return false;
244  }
245  }
246  catch (const std::exception& ex) {
247  std::cerr << ex.what() << std::endl;
248  return false;
249  }
250 
251  // lsa-refresh-time
252  uint32_t lsaRefreshTime = section.get<uint32_t>("lsa-refresh-time", LSA_REFRESH_TIME_DEFAULT);
253 
254  if (lsaRefreshTime >= LSA_REFRESH_TIME_MIN && lsaRefreshTime <= LSA_REFRESH_TIME_MAX) {
255  m_nlsr.getConfParameter().setLsaRefreshTime(lsaRefreshTime);
256  }
257  else {
258  std::cerr << "Wrong value for lsa-refresh-time ";
259  std::cerr << "Allowed value: " << LSA_REFRESH_TIME_MIN << "-";;
260  std::cerr << LSA_REFRESH_TIME_MAX << std::endl;
261 
262  return false;
263  }
264 
265  // router-dead-interval
266  uint32_t routerDeadInterval = section.get<uint32_t>("router-dead-interval", (2*lsaRefreshTime));
267 
268  if (routerDeadInterval > m_nlsr.getConfParameter().getLsaRefreshTime()) {
269  m_nlsr.getConfParameter().setRouterDeadInterval(routerDeadInterval);
270  }
271  else {
272  std::cerr << "Value of router-dead-interval must be larger than lsa-refresh-time" << std::endl;
273  return false;
274  }
275 
276  // lsa-interest-lifetime
277  int lifetime = section.get<int>("lsa-interest-lifetime", LSA_INTEREST_LIFETIME_DEFAULT);
278 
279  if (lifetime >= LSA_INTEREST_LIFETIME_MIN && lifetime <= LSA_INTEREST_LIFETIME_MAX) {
280  m_nlsr.getConfParameter().setLsaInterestLifetime(ndn::time::seconds(lifetime));
281  }
282  else {
283  std::cerr << "Wrong value for lsa-interest-timeout. "
284  << "Allowed value:" << LSA_INTEREST_LIFETIME_MIN << "-"
285  << LSA_INTEREST_LIFETIME_MAX << std::endl;
286 
287  return false;
288  }
289 
290  // log-level
291  std::string logLevel = section.get<std::string>("log-level", "INFO");
292 
293  if (isValidLogLevel(logLevel)) {
294  m_nlsr.getConfParameter().setLogLevel(logLevel);
295  }
296  else {
297  std::cerr << "Invalid value for log-level ";
298  std::cerr << "Valid values: ALL, TRACE, DEBUG, INFO, WARN, ERROR, NONE" << std::endl;
299  return false;
300  }
301 
302  try {
303  std::string logDir = section.get<std::string>("log-dir");
304  if (boost::filesystem::exists(logDir)) {
305  if (boost::filesystem::is_directory(logDir)) {
306  std::string testFileName=logDir+"/test.log";
307  std::ofstream testOutFile;
308  testOutFile.open(testFileName.c_str());
309  if (testOutFile.is_open() && testOutFile.good()) {
310  m_nlsr.getConfParameter().setLogDir(logDir);
311  }
312  else {
313  std::cerr << "User does not have read and write permission on the directory";
314  std::cerr << std::endl;
315  return false;
316  }
317  testOutFile.close();
318  remove(testFileName.c_str());
319  }
320  else {
321  std::cerr << "Provided path is not a directory" << std::endl;
322  return false;
323  }
324  }
325  else {
326  std::cerr << "Provided log directory <" << logDir << "> does not exist" << std::endl;
327  return false;
328  }
329  }
330  catch (const std::exception& ex) {
331  std::cerr << "You must configure log directory" << std::endl;
332  std::cerr << ex.what() << std::endl;
333  return false;
334  }
335 
336  try {
337  std::string seqDir = section.get<std::string>("seq-dir");
338  if (boost::filesystem::exists(seqDir)) {
339  if (boost::filesystem::is_directory(seqDir)) {
340  std::string testFileName=seqDir+"/test.seq";
341  std::ofstream testOutFile;
342  testOutFile.open(testFileName.c_str());
343  if (testOutFile.is_open() && testOutFile.good()) {
344  m_nlsr.getConfParameter().setSeqFileDir(seqDir);
345  }
346  else {
347  std::cerr << "User does not have read and write permission on the directory";
348  std::cerr << std::endl;
349  return false;
350  }
351  testOutFile.close();
352  remove(testFileName.c_str());
353  }
354  else {
355  std::cerr << "Provided path is not a directory" << std::endl;
356  return false;
357  }
358  }
359  else {
360  std::cerr << "Provided sequence directory <" << seqDir << "> does not exist" << std::endl;
361  return false;
362  }
363  }
364  catch (const std::exception& ex) {
365  std::cerr << "You must configure sequence directory" << std::endl;
366  std::cerr << ex.what() << std::endl;
367  return false;
368  }
369 
370  try {
371  std::string log4cxxPath = section.get<std::string>("log4cxx-conf");
372 
373  if (log4cxxPath == "") {
374  std::cerr << "No value provided for log4cxx-conf" << std::endl;
375  return false;
376  }
377 
378  if (boost::filesystem::exists(log4cxxPath)) {
379  m_nlsr.getConfParameter().setLog4CxxConfPath(log4cxxPath);
380  }
381  else {
382  std::cerr << "Provided path for log4cxx-conf <" << log4cxxPath
383  << "> does not exist" << std::endl;
384 
385  return false;
386  }
387  }
388  catch (const std::exception& ex) {
389  // Variable is optional so default configuration will be used; continue processing file
390  }
391 
392  return true;
393 }
394 
395 bool
396 ConfFileProcessor::processConfSectionNeighbors(const ConfigSection& section)
397 {
398  // hello-retries
399  int retrials = section.get<int>("hello-retries", HELLO_RETRIES_DEFAULT);
400 
401  if (retrials >= HELLO_RETRIES_MIN && retrials <= HELLO_RETRIES_MAX) {
402  m_nlsr.getConfParameter().setInterestRetryNumber(retrials);
403  }
404  else {
405  std::cerr << "Wrong value for hello-retries." << std::endl;
406  std::cerr << "Allowed value:" << HELLO_RETRIES_MIN << "-";
407  std::cerr << HELLO_RETRIES_MAX << std::endl;
408 
409  return false;
410  }
411 
412  // hello-timeout
413  uint32_t timeOut = section.get<uint32_t>("hello-timeout", HELLO_TIMEOUT_DEFAULT);
414 
415  if (timeOut >= HELLO_TIMEOUT_MIN && timeOut <= HELLO_TIMEOUT_MAX) {
416  m_nlsr.getConfParameter().setInterestResendTime(timeOut);
417  }
418  else {
419  std::cerr << "Wrong value for hello-timeout. ";
420  std::cerr << "Allowed value:" << HELLO_TIMEOUT_MIN << "-";
421  std::cerr << HELLO_TIMEOUT_MAX << std::endl;
422 
423  return false;
424  }
425 
426  // hello-interval
427  uint32_t interval = section.get<uint32_t>("hello-interval", HELLO_INTERVAL_DEFAULT);
428 
429  if (interval >= HELLO_INTERVAL_MIN && interval <= HELLO_INTERVAL_MAX) {
430  m_nlsr.getConfParameter().setInfoInterestInterval(interval);
431  }
432  else {
433  std::cerr << "Wrong value for hello-interval. ";
434  std::cerr << "Allowed value:" << HELLO_INTERVAL_MIN << "-";
435  std::cerr << HELLO_INTERVAL_MAX << std::endl;
436 
437  return false;
438  }
439 
440  // Event intervals
441  // adj-lsa-build-interval
442  ConfigurationVariable<uint32_t> adjLsaBuildInterval("adj-lsa-build-interval",
444  &m_nlsr.getConfParameter(), _1));
446  adjLsaBuildInterval.setOptional(ADJ_LSA_BUILD_INTERVAL_DEFAULT);
447 
448  if (!adjLsaBuildInterval.parseFromConfigSection(section)) {
449  return false;
450  }
451  // Set the retry count for fetching the FaceStatus dataset
452  ConfigurationVariable<uint32_t> faceDatasetFetchTries("face-dataset-fetch-tries",
454  &m_nlsr.getConfParameter(),
455  _1));
456 
457  faceDatasetFetchTries.setMinAndMaxValue(FACE_DATASET_FETCH_TRIES_MIN,
459  faceDatasetFetchTries.setOptional(FACE_DATASET_FETCH_TRIES_DEFAULT);
460 
461  if (!faceDatasetFetchTries.parseFromConfigSection(section)) {
462  return false;
463  }
464 
465  // Set the interval between FaceStatus dataset fetch attempts.
466  ConfigurationVariable<uint32_t> faceDatasetFetchInterval("face-dataset-fetch-interval",
468  &m_nlsr.getConfParameter(),
469  _1));
470 
471  faceDatasetFetchInterval.setMinAndMaxValue(FACE_DATASET_FETCH_INTERVAL_MIN,
473  faceDatasetFetchInterval.setOptional(FACE_DATASET_FETCH_INTERVAL_DEFAULT);
474 
475  if (!faceDatasetFetchInterval.parseFromConfigSection(section)) {
476  return false;
477  }
478 
479  // first-hello-interval
480  ConfigurationVariable<uint32_t> firstHelloInterval("first-hello-interval",
482  &m_nlsr.getConfParameter(), _1));
484  firstHelloInterval.setOptional(FIRST_HELLO_INTERVAL_DEFAULT);
485 
486  if (!firstHelloInterval.parseFromConfigSection(section)) {
487  return false;
488  }
489 
490  for (ConfigSection::const_iterator tn =
491  section.begin(); tn != section.end(); ++tn) {
492 
493  if (tn->first == "neighbor") {
494  try {
495  ConfigSection CommandAttriTree = tn->second;
496  std::string name = CommandAttriTree.get<std::string>("name");
497  std::string uriString = CommandAttriTree.get<std::string>("face-uri");
498 
499  ndn::FaceUri faceUri;
500  if (! faceUri.parse(uriString)) {
501  std::cerr << "parsing failed!" << std::endl;
502  return false;
503  }
504 
505  double linkCost = CommandAttriTree.get<double>("link-cost",
507  ndn::Name neighborName(name);
508  if (!neighborName.empty()) {
509  Adjacent adj(name, faceUri, linkCost, Adjacent::STATUS_INACTIVE, 0, 0);
510  m_nlsr.getAdjacencyList().insert(adj);
511  }
512  else {
513  std::cerr << " Wrong command format ! [name /nbr/name/ \n face-uri /uri\n]";
514  std::cerr << " or bad URI format" << std::endl;
515  }
516  }
517  catch (const std::exception& ex) {
518  std::cerr << ex.what() << std::endl;
519  return false;
520  }
521  }
522  }
523  return true;
524 }
525 
526 bool
527 ConfFileProcessor::processConfSectionHyperbolic(const ConfigSection& section)
528 {
529  // state
530  std::string state = section.get<std::string>("state", "off");
531 
532  if (boost::iequals(state, "off")) {
533  m_nlsr.getConfParameter().setHyperbolicState(HYPERBOLIC_STATE_OFF);
534  }
535  else if (boost::iequals(state, "on")) {
536  m_nlsr.getConfParameter().setHyperbolicState(HYPERBOLIC_STATE_ON);
537  }
538  else if (state == "dry-run") {
539  m_nlsr.getConfParameter().setHyperbolicState(HYPERBOLIC_STATE_DRY_RUN);
540  }
541  else {
542  std::cerr << "Wrong format for hyperbolic state." << std::endl;
543  std::cerr << "Allowed value: off, on, dry-run" << std::endl;
544 
545  return false;
546  }
547 
548  try {
549  // Radius and angle(s) are mandatory configuration parameters in hyperbolic section.
550  // Even if router can have hyperbolic routing calculation off but other router
551  // in the network may use hyperbolic routing calculation for FIB generation.
552  // So each router need to advertise its hyperbolic coordinates in the network
553  double radius = section.get<double>("radius");
554  std::string angleString = section.get<std::string>("angle");
555 
556  std::stringstream ss(angleString);
557  std::vector<double> angles;
558 
559  double angle;
560 
561  while (ss >> angle) {
562  angles.push_back(angle);
563  if (ss.peek() == ',' || ss.peek() == ' ') {
564  ss.ignore();
565  }
566  }
567 
568  if (!m_nlsr.getConfParameter().setCorR(radius)) {
569  return false;
570  }
571  m_nlsr.getConfParameter().setCorTheta(angles);
572  }
573  catch (const std::exception& ex) {
574  std::cerr << ex.what() << std::endl;
575  if (state == "on" || state == "dry-run") {
576  return false;
577  }
578  }
579 
580  return true;
581 }
582 
583 bool
584 ConfFileProcessor::processConfSectionFib(const ConfigSection& section)
585 {
586  // max-faces-per-prefix
587  int maxFacesPerPrefix = section.get<int>("max-faces-per-prefix", MAX_FACES_PER_PREFIX_DEFAULT);
588 
589  if (maxFacesPerPrefix >= MAX_FACES_PER_PREFIX_MIN &&
590  maxFacesPerPrefix <= MAX_FACES_PER_PREFIX_MAX)
591  {
592  m_nlsr.getConfParameter().setMaxFacesPerPrefix(maxFacesPerPrefix);
593  }
594  else {
595  std::cerr << "Wrong value for max-faces-per-prefix. ";
596  std::cerr << MAX_FACES_PER_PREFIX_MIN << std::endl;
597 
598  return false;
599  }
600 
601  // routing-calc-interval
602  ConfigurationVariable<uint32_t> routingCalcInterval("routing-calc-interval",
604  &m_nlsr.getConfParameter(), _1));
606  routingCalcInterval.setOptional(ROUTING_CALC_INTERVAL_DEFAULT);
607 
608  if (!routingCalcInterval.parseFromConfigSection(section)) {
609  return false;
610  }
611 
612  return true;
613 }
614 
615 bool
616 ConfFileProcessor::processConfSectionAdvertising(const ConfigSection& section)
617 {
618  for (ConfigSection::const_iterator tn =
619  section.begin(); tn != section.end(); ++tn) {
620  if (tn->first == "prefix") {
621  try {
622  std::string prefix = tn->second.data();
623  ndn::Name namePrefix(prefix);
624  if (!namePrefix.empty()) {
625  m_nlsr.getNamePrefixList().insert(namePrefix);
626  }
627  else {
628  std::cerr << " Wrong command format ! [prefix /name/prefix] or bad URI" << std::endl;
629  return false;
630  }
631  }
632  catch (const std::exception& ex) {
633  std::cerr << ex.what() << std::endl;
634  return false;
635  }
636  }
637  }
638  return true;
639 }
640 
641 bool
642 ConfFileProcessor::processConfSectionSecurity(const ConfigSection& section)
643 {
644  ConfigSection::const_iterator it = section.begin();
645 
646  if (it == section.end() || it->first != "validator") {
647  std::cerr << "Error: Expect validator section!" << std::endl;
648  return false;
649  }
650 
651  m_nlsr.loadValidator(it->second, m_confFileName);
652 
653  it++;
654  if (it != section.end() && it->first == "prefix-update-validator") {
655  m_nlsr.getPrefixUpdateProcessor().loadValidator(it->second, m_confFileName);
656 
657  it++;
658  for (; it != section.end(); it++) {
659  using namespace boost::filesystem;
660 
661  if (it->first != "cert-to-publish") {
662  std::cerr << "Error: Expect cert-to-publish!" << std::endl;
663  return false;
664  }
665 
666  std::string file = it->second.data();
667  path certfilePath = absolute(file, path(m_confFileName).parent_path());
668  std::shared_ptr<ndn::security::v2::Certificate> idCert =
669  ndn::io::load<ndn::security::v2::Certificate>(certfilePath.string());
670 
671  if (idCert == nullptr) {
672  std::cerr << "Error: Cannot load cert-to-publish: " << file << "!" << std::endl;
673  return false;
674  }
675 
676  m_nlsr.loadCertToPublish(*idCert);
677  }
678  }
679 
680  return true;
681 }
682 
683 } // namespace nlsr
bool isValidLogLevel(const std::string &logLevel)
Definition: logger.cpp:80
static const float DEFAULT_LINK_COST
Definition: adjacent.hpp:164
void setRoutingCalcInterval(uint32_t interval)
void setAdjLsaBuildInterval(uint32_t interval)
ConfigurationVariable(const std::string &key, const ConfParameterCallback &setter)
boost::property_tree::ptree ConfigSection
void setFaceDatasetFetchInterval(uint32_t interval)
void setMinAndMaxValue(T min, T max)
A neighbor reachable over a Face.
Definition: adjacent.hpp:38
void setOptional(T defaultValue)
Copyright (c) 2014-2017, The University of Memphis, Regents of the University of California, Arizona Board of Regents.
void setFirstHelloInterval(uint32_t interval)
void setFaceDatasetFetchTries(uint32_t count)
std::function< void(T)> ConfParameterCallback
bool parseFromConfigSection(const ConfigSection &section)
bool processConfFile()
Load and parse the configuration file, then populate NLSR.