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  uint32_t syncInterestLifetime = section.get<uint32_t>("sync-interest-lifetime", SYNC_INTEREST_LIFETIME_DEFAULT);
291  if (syncInterestLifetime >= SYNC_INTEREST_LIFETIME_MIN &&
292  syncInterestLifetime <= SYNC_INTEREST_LIFETIME_MAX) {
293  m_nlsr.getConfParameter().setSyncInterestLifetime(syncInterestLifetime);
294  }
295  else {
296  std::cerr << "Wrong value for sync-interest-lifetime. "
297  << "Allowed value:" << SYNC_INTEREST_LIFETIME_MIN << "-"
298  << SYNC_INTEREST_LIFETIME_MAX << std::endl;
299 
300  return false;
301  }
302 
303  try {
304  std::string seqDir = section.get<std::string>("seq-dir");
305  if (boost::filesystem::exists(seqDir)) {
306  if (boost::filesystem::is_directory(seqDir)) {
307  std::string testFileName=seqDir+"/test.seq";
308  std::ofstream testOutFile;
309  testOutFile.open(testFileName.c_str());
310  if (testOutFile.is_open() && testOutFile.good()) {
311  m_nlsr.getConfParameter().setSeqFileDir(seqDir);
312  }
313  else {
314  std::cerr << "User does not have read and write permission on the directory";
315  std::cerr << std::endl;
316  return false;
317  }
318  testOutFile.close();
319  remove(testFileName.c_str());
320  }
321  else {
322  std::cerr << "Provided path is not a directory" << std::endl;
323  return false;
324  }
325  }
326  else {
327  std::cerr << "Provided sequence directory <" << seqDir << "> does not exist" << std::endl;
328  return false;
329  }
330  }
331  catch (const std::exception& ex) {
332  std::cerr << "You must configure sequence directory" << std::endl;
333  std::cerr << ex.what() << std::endl;
334  return false;
335  }
336 
337  return true;
338 }
339 
340 bool
341 ConfFileProcessor::processConfSectionNeighbors(const ConfigSection& section)
342 {
343  // hello-retries
344  int retrials = section.get<int>("hello-retries", HELLO_RETRIES_DEFAULT);
345 
346  if (retrials >= HELLO_RETRIES_MIN && retrials <= HELLO_RETRIES_MAX) {
347  m_nlsr.getConfParameter().setInterestRetryNumber(retrials);
348  }
349  else {
350  std::cerr << "Wrong value for hello-retries." << std::endl;
351  std::cerr << "Allowed value:" << HELLO_RETRIES_MIN << "-";
352  std::cerr << HELLO_RETRIES_MAX << std::endl;
353 
354  return false;
355  }
356 
357  // hello-timeout
358  uint32_t timeOut = section.get<uint32_t>("hello-timeout", HELLO_TIMEOUT_DEFAULT);
359 
360  if (timeOut >= HELLO_TIMEOUT_MIN && timeOut <= HELLO_TIMEOUT_MAX) {
361  m_nlsr.getConfParameter().setInterestResendTime(timeOut);
362  }
363  else {
364  std::cerr << "Wrong value for hello-timeout. ";
365  std::cerr << "Allowed value:" << HELLO_TIMEOUT_MIN << "-";
366  std::cerr << HELLO_TIMEOUT_MAX << std::endl;
367 
368  return false;
369  }
370 
371  // hello-interval
372  uint32_t interval = section.get<uint32_t>("hello-interval", HELLO_INTERVAL_DEFAULT);
373 
374  if (interval >= HELLO_INTERVAL_MIN && interval <= HELLO_INTERVAL_MAX) {
375  m_nlsr.getConfParameter().setInfoInterestInterval(interval);
376  }
377  else {
378  std::cerr << "Wrong value for hello-interval. ";
379  std::cerr << "Allowed value:" << HELLO_INTERVAL_MIN << "-";
380  std::cerr << HELLO_INTERVAL_MAX << std::endl;
381 
382  return false;
383  }
384 
385  // Event intervals
386  // adj-lsa-build-interval
387  ConfigurationVariable<uint32_t> adjLsaBuildInterval("adj-lsa-build-interval",
389  &m_nlsr.getConfParameter(), _1));
391  adjLsaBuildInterval.setOptional(ADJ_LSA_BUILD_INTERVAL_DEFAULT);
392 
393  if (!adjLsaBuildInterval.parseFromConfigSection(section)) {
394  return false;
395  }
396  // Set the retry count for fetching the FaceStatus dataset
397  ConfigurationVariable<uint32_t> faceDatasetFetchTries("face-dataset-fetch-tries",
399  &m_nlsr.getConfParameter(),
400  _1));
401 
402  faceDatasetFetchTries.setMinAndMaxValue(FACE_DATASET_FETCH_TRIES_MIN,
404  faceDatasetFetchTries.setOptional(FACE_DATASET_FETCH_TRIES_DEFAULT);
405 
406  if (!faceDatasetFetchTries.parseFromConfigSection(section)) {
407  return false;
408  }
409 
410  // Set the interval between FaceStatus dataset fetch attempts.
411  ConfigurationVariable<uint32_t> faceDatasetFetchInterval("face-dataset-fetch-interval",
413  &m_nlsr.getConfParameter(),
414  _1));
415 
416  faceDatasetFetchInterval.setMinAndMaxValue(FACE_DATASET_FETCH_INTERVAL_MIN,
418  faceDatasetFetchInterval.setOptional(FACE_DATASET_FETCH_INTERVAL_DEFAULT);
419 
420  if (!faceDatasetFetchInterval.parseFromConfigSection(section)) {
421  return false;
422  }
423 
424  // first-hello-interval
425  ConfigurationVariable<uint32_t> firstHelloInterval("first-hello-interval",
427  &m_nlsr.getConfParameter(), _1));
429  firstHelloInterval.setOptional(FIRST_HELLO_INTERVAL_DEFAULT);
430 
431  if (!firstHelloInterval.parseFromConfigSection(section)) {
432  return false;
433  }
434 
435  for (ConfigSection::const_iterator tn =
436  section.begin(); tn != section.end(); ++tn) {
437 
438  if (tn->first == "neighbor") {
439  try {
440  ConfigSection CommandAttriTree = tn->second;
441  std::string name = CommandAttriTree.get<std::string>("name");
442  std::string uriString = CommandAttriTree.get<std::string>("face-uri");
443 
444  ndn::FaceUri faceUri;
445  if (! faceUri.parse(uriString)) {
446  std::cerr << "parsing failed!" << std::endl;
447  return false;
448  }
449 
450  double linkCost = CommandAttriTree.get<double>("link-cost",
452  ndn::Name neighborName(name);
453  if (!neighborName.empty()) {
454  Adjacent adj(name, faceUri, linkCost, Adjacent::STATUS_INACTIVE, 0, 0);
455  m_nlsr.getAdjacencyList().insert(adj);
456  }
457  else {
458  std::cerr << " Wrong command format ! [name /nbr/name/ \n face-uri /uri\n]";
459  std::cerr << " or bad URI format" << std::endl;
460  }
461  }
462  catch (const std::exception& ex) {
463  std::cerr << ex.what() << std::endl;
464  return false;
465  }
466  }
467  }
468  return true;
469 }
470 
471 bool
472 ConfFileProcessor::processConfSectionHyperbolic(const ConfigSection& section)
473 {
474  // state
475  std::string state = section.get<std::string>("state", "off");
476 
477  if (boost::iequals(state, "off")) {
478  m_nlsr.getConfParameter().setHyperbolicState(HYPERBOLIC_STATE_OFF);
479  }
480  else if (boost::iequals(state, "on")) {
481  m_nlsr.getConfParameter().setHyperbolicState(HYPERBOLIC_STATE_ON);
482  }
483  else if (state == "dry-run") {
484  m_nlsr.getConfParameter().setHyperbolicState(HYPERBOLIC_STATE_DRY_RUN);
485  }
486  else {
487  std::cerr << "Wrong format for hyperbolic state." << std::endl;
488  std::cerr << "Allowed value: off, on, dry-run" << std::endl;
489 
490  return false;
491  }
492 
493  try {
494  // Radius and angle(s) are mandatory configuration parameters in hyperbolic section.
495  // Even if router can have hyperbolic routing calculation off but other router
496  // in the network may use hyperbolic routing calculation for FIB generation.
497  // So each router need to advertise its hyperbolic coordinates in the network
498  double radius = section.get<double>("radius");
499  std::string angleString = section.get<std::string>("angle");
500 
501  std::stringstream ss(angleString);
502  std::vector<double> angles;
503 
504  double angle;
505 
506  while (ss >> angle) {
507  angles.push_back(angle);
508  if (ss.peek() == ',' || ss.peek() == ' ') {
509  ss.ignore();
510  }
511  }
512 
513  if (!m_nlsr.getConfParameter().setCorR(radius)) {
514  return false;
515  }
516  m_nlsr.getConfParameter().setCorTheta(angles);
517  }
518  catch (const std::exception& ex) {
519  std::cerr << ex.what() << std::endl;
520  if (state == "on" || state == "dry-run") {
521  return false;
522  }
523  }
524 
525  return true;
526 }
527 
528 bool
529 ConfFileProcessor::processConfSectionFib(const ConfigSection& section)
530 {
531  // max-faces-per-prefix
532  int maxFacesPerPrefix = section.get<int>("max-faces-per-prefix", MAX_FACES_PER_PREFIX_DEFAULT);
533 
534  if (maxFacesPerPrefix >= MAX_FACES_PER_PREFIX_MIN &&
535  maxFacesPerPrefix <= MAX_FACES_PER_PREFIX_MAX)
536  {
537  m_nlsr.getConfParameter().setMaxFacesPerPrefix(maxFacesPerPrefix);
538  }
539  else {
540  std::cerr << "Wrong value for max-faces-per-prefix. ";
541  std::cerr << MAX_FACES_PER_PREFIX_MIN << std::endl;
542 
543  return false;
544  }
545 
546  // routing-calc-interval
547  ConfigurationVariable<uint32_t> routingCalcInterval("routing-calc-interval",
549  &m_nlsr.getConfParameter(), _1));
551  routingCalcInterval.setOptional(ROUTING_CALC_INTERVAL_DEFAULT);
552 
553  if (!routingCalcInterval.parseFromConfigSection(section)) {
554  return false;
555  }
556 
557  return true;
558 }
559 
560 bool
561 ConfFileProcessor::processConfSectionAdvertising(const ConfigSection& section)
562 {
563  for (ConfigSection::const_iterator tn =
564  section.begin(); tn != section.end(); ++tn) {
565  if (tn->first == "prefix") {
566  try {
567  std::string prefix = tn->second.data();
568  ndn::Name namePrefix(prefix);
569  if (!namePrefix.empty()) {
570  m_nlsr.getNamePrefixList().insert(namePrefix);
571  }
572  else {
573  std::cerr << " Wrong command format ! [prefix /name/prefix] or bad URI" << std::endl;
574  return false;
575  }
576  }
577  catch (const std::exception& ex) {
578  std::cerr << ex.what() << std::endl;
579  return false;
580  }
581  }
582  }
583  return true;
584 }
585 
586 bool
587 ConfFileProcessor::processConfSectionSecurity(const ConfigSection& section)
588 {
589  ConfigSection::const_iterator it = section.begin();
590 
591  if (it == section.end() || it->first != "validator") {
592  std::cerr << "Error: Expect validator section!" << std::endl;
593  return false;
594  }
595 
596  m_nlsr.loadValidator(it->second, m_confFileName);
597 
598  it++;
599  if (it != section.end() && it->first == "prefix-update-validator") {
600  m_nlsr.getPrefixUpdateProcessor().loadValidator(it->second, m_confFileName);
601 
602  it++;
603  for (; it != section.end(); it++) {
604  using namespace boost::filesystem;
605 
606  if (it->first != "cert-to-publish") {
607  std::cerr << "Error: Expect cert-to-publish!" << std::endl;
608  return false;
609  }
610 
611  std::string file = it->second.data();
612  path certfilePath = absolute(file, path(m_confFileName).parent_path());
613  std::shared_ptr<ndn::security::v2::Certificate> idCert =
614  ndn::io::load<ndn::security::v2::Certificate>(certfilePath.string());
615 
616  if (idCert == nullptr) {
617  std::cerr << "Error: Cannot load cert-to-publish: " << file << "!" << std::endl;
618  return false;
619  }
620 
621  m_nlsr.loadCertToPublish(*idCert);
622  }
623  }
624 
625  return true;
626 }
627 
628 } // namespace nlsr
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-2018, 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.