Add support for setting NLSR prefix costs via configuration file and nlsrc

This change alters the nlsr.conf 'advertising' format, as the previous
setup used unnecessary keys which made dynamically adjusting the
stateful conf file difficult.

Incorporates code written by Yanbiao Li.

Change-Id: I3ed5d0a564099be8cc1389ee6acc6f2d04cef889
diff --git a/src/update/command-processor.cpp b/src/update/command-processor.cpp
index f260bd6..95290d5 100644
--- a/src/update/command-processor.cpp
+++ b/src/update/command-processor.cpp
@@ -56,7 +56,7 @@
     m_lsdb.buildAndInstallOwnNameLsa();
     if (castParams.hasFlags() && castParams.getFlags() == PREFIX_FLAG) {
       NLSR_LOG_INFO("Saving name to the configuration file ");
-      auto [afterAdvertiseReturn, afterAdvertiseMessage] = afterAdvertise(castParams.getName());
+      auto [afterAdvertiseReturn, afterAdvertiseMessage] = afterAdvertise(castParams.getName(), castParamCost);
       if (afterAdvertiseReturn) {
         return done(ndn::nfd::ControlResponse(205, afterAdvertiseMessage).setBody(responseParams.wireEncode()));
       }
@@ -71,7 +71,7 @@
     if (castParams.hasFlags() && castParams.getFlags() == PREFIX_FLAG) {
       // Save an already advertised prefix
       NLSR_LOG_INFO("Saving an already advertised name: " << castParams.getName());
-      auto [afterAdvertiseReturn, afterAdvertiseMessage] = afterAdvertise(castParams.getName());
+      auto [afterAdvertiseReturn, afterAdvertiseMessage] = afterAdvertise(castParams.getName(), castParamCost);
       if (afterAdvertiseReturn) {
         return done(ndn::nfd::ControlResponse(205, afterAdvertiseMessage).setBody(responseParams.wireEncode()));
       }
diff --git a/src/update/command-processor.hpp b/src/update/command-processor.hpp
index 1d25ec0..0973839 100644
--- a/src/update/command-processor.hpp
+++ b/src/update/command-processor.hpp
@@ -70,7 +70,7 @@
    *  \return tuple {bool indicating success/failure, message string}.
    */
   virtual std::tuple<bool, std::string>
-  afterAdvertise(const ndn::Name& prefix)
+  afterAdvertise(const ndn::Name& prefix, uint64_t cost)
   {
     return {true, "OK"};
   }
diff --git a/src/update/prefix-update-commands.cpp b/src/update/prefix-update-commands.cpp
index da43fe7..0e2c3d6 100644
--- a/src/update/prefix-update-commands.cpp
+++ b/src/update/prefix-update-commands.cpp
@@ -26,10 +26,12 @@
 const AdvertisePrefixCommand::RequestFormat AdvertisePrefixCommand::s_requestFormat =
     RequestFormat()
     .required(ndn::nfd::CONTROL_PARAMETER_NAME)
+    .optional(ndn::nfd::CONTROL_PARAMETER_COST)
     .optional(ndn::nfd::CONTROL_PARAMETER_FLAGS);
 const AdvertisePrefixCommand::ResponseFormat AdvertisePrefixCommand::s_responseFormat =
     ResponseFormat()
     .required(ndn::nfd::CONTROL_PARAMETER_NAME)
+    .optional(ndn::nfd::CONTROL_PARAMETER_COST)
     .optional(ndn::nfd::CONTROL_PARAMETER_FLAGS);
 
 const WithdrawPrefixCommand::RequestFormat WithdrawPrefixCommand::s_requestFormat =
diff --git a/src/update/prefix-update-processor.cpp b/src/update/prefix-update-processor.cpp
index 2f403fb..2bec0ae 100644
--- a/src/update/prefix-update-processor.cpp
+++ b/src/update/prefix-update-processor.cpp
@@ -22,6 +22,7 @@
 #include "prefix-update-processor.hpp"
 #include "logger.hpp"
 #include "prefix-update-commands.hpp"
+#include "utility/boost-info-editor.hpp"
 
 #include <boost/algorithm/string.hpp>
 #include <fstream>
@@ -115,33 +116,25 @@
 }
 
 std::tuple<bool, std::string>
-PrefixUpdateProcessor::addOrDeletePrefix(const ndn::Name& prefix, bool addPrefix)
+PrefixUpdateProcessor::addOrDeletePrefix(const ndn::Name& prefix, uint64_t cost, bool addPrefix)
 {
-  std::string value = " prefix " + prefix.toUri();
-  std::string fileString;
-  std::string line;
-  std::string trimedLine;
+  std::string section = "advertising." + prefix.toUri();
+  std::string value = "    " + prefix.toUri() + " " + std::to_string(cost);
   std::fstream input(m_confFileNameDynamic, input.in);
   if (!input.good() || !input.is_open()) {
     NLSR_LOG_ERROR("Failed to open configuration file for parsing");
     return {false, "Failed to open configuration file for parsing"};
   }
-
+  input.close();
   if (addPrefix) {
     //check if prefix already exist in the nlsr configuration file
     if (checkForPrefixInFile(value)) {
       NLSR_LOG_ERROR("Prefix already exists in the configuration file");
       return {false, "Prefix already exists in the configuration file"};
     }
-    while (!input.eof()) {
-      getline(input, line);
-      if (!line.empty()) {
-        fileString.append(line + "\n");
-        if (line == "advertising") {
-          getline(input, line);
-          fileString.append(line + "\n" + value + "\n");
-        }
-      }
+    if (!util::boost_info_editor::put(m_confFileNameDynamic, section, std::to_string(cost))) {
+      NLSR_LOG_ERROR("Unable to save changes to configuration file");
+      return {false, "Unable to save changes to configuration file"};
     }
   }
   else {
@@ -149,35 +142,25 @@
       NLSR_LOG_ERROR("Prefix doesn't exists in the configuration file");
       return {false, "Prefix doesn't exists in the configuration file"};
     }
-    boost::trim(value);
-    while (!input.eof()) {
-      getline(input, line);
-      if (!line.empty()) {
-        std::string trimLine = line;
-        boost::trim(trimLine);
-        if (trimLine != value) {
-          fileString.append(line + "\n");
-        }
-      }
+    if (!util::boost_info_editor::remove(m_confFileNameDynamic, section)) {
+      NLSR_LOG_ERROR("Unable to save changes to configuration file");
+      return {false, "Unable to save changes to configuration file"};
     }
   }
-  input.close();
-  std::ofstream output(m_confFileNameDynamic);
-  output << fileString;
-  output.close();
+
   return {true, "OK"};
 }
 
 std::tuple<bool, std::string>
-PrefixUpdateProcessor::afterAdvertise(const ndn::Name& prefix)
+PrefixUpdateProcessor::afterAdvertise(const ndn::Name& prefix, uint64_t cost)
 {
-  return addOrDeletePrefix(prefix, true);
+  return addOrDeletePrefix(prefix, cost, true);
 }
 
 std::tuple<bool, std::string>
 PrefixUpdateProcessor::afterWithdraw(const ndn::Name& prefix)
 {
-  return addOrDeletePrefix(prefix, false);
+  return addOrDeletePrefix(prefix, 0, false);
 }
 
 } // namespace nlsr::update
diff --git a/src/update/prefix-update-processor.hpp b/src/update/prefix-update-processor.hpp
index bc05937..1d937b1 100644
--- a/src/update/prefix-update-processor.hpp
+++ b/src/update/prefix-update-processor.hpp
@@ -58,13 +58,13 @@
    * configuration file
    */
   std::tuple<bool, std::string>
-  addOrDeletePrefix(const ndn::Name& prefix, bool addPrefix);
+  addOrDeletePrefix(const ndn::Name& prefix, uint64_t cost, bool addPrefix);
 
   /*! \brief Save an advertised prefix to the nlsr configuration file.
    *  \return tuple {bool indicating success/failure, message string}.
    */
   std::tuple<bool, std::string>
-  afterAdvertise(const ndn::Name& prefix) override;
+  afterAdvertise(const ndn::Name& prefix, uint64_t cost) override;
 
   /*! \brief Remove an advertised prefix from the nlsr configuration file.
    *  \return tuple {bool indicating success/failure, message string}.