update: Disable PrefixUpdateProcessor when validator is not in config

refs: 2814

Change-Id: I2669dcd4af36ebe09f3e20189a99c812e0e6ad7b
diff --git a/src/conf-file-processor.cpp b/src/conf-file-processor.cpp
index 2bb7aef..c4cb20b 100644
--- a/src/conf-file-processor.cpp
+++ b/src/conf-file-processor.cpp
@@ -612,46 +612,40 @@
 {
   ConfigSection::const_iterator it = section.begin();
 
-  if (it == section.end() || it->first != "validator")
-    {
-      std::cerr << "Error: Expect validator section!" << std::endl;
-      return false;
-    }
+  if (it == section.end() || it->first != "validator") {
+    std::cerr << "Error: Expect validator section!" << std::endl;
+    return false;
+  }
 
   m_nlsr.loadValidator(it->second, m_confFileName);
+
   it++;
+  if (it != section.end() && it->first == "prefix-update-validator") {
+    m_nlsr.getPrefixUpdateProcessor().enable();
+    m_nlsr.getPrefixUpdateProcessor().loadValidator(it->second, m_confFileName);
 
-  if (it == section.end() || it->first != "prefix-update-validator")
-    {
-      std::cerr << "Error: Expect prefix-update-validator section" << std::endl;
-      return false;
-    }
-
-  m_nlsr.getPrefixUpdateProcessor().loadValidator(it->second, m_confFileName);
-  it++;
-
-  for (; it != section.end(); it++)
-    {
+    it++;
+    for (; it != section.end(); it++) {
       using namespace boost::filesystem;
-      if (it->first != "cert-to-publish")
-        {
-          std::cerr << "Error: Expect cert-to-publish!" << std::endl;
-          return false;
-        }
+
+      if (it->first != "cert-to-publish") {
+        std::cerr << "Error: Expect cert-to-publish!" << std::endl;
+        return false;
+      }
 
       std::string file = it->second.data();
       path certfilePath = absolute(file, path(m_confFileName).parent_path());
-      ndn::shared_ptr<ndn::IdentityCertificate> idCert =
+      shared_ptr<ndn::IdentityCertificate> idCert =
         ndn::io::load<ndn::IdentityCertificate>(certfilePath.string());
 
-      if (!static_cast<bool>(idCert))
-        {
-          std::cerr << "Error: Cannot load cert-to-publish: " << file << "!" << std::endl;
-          return false;
-        }
+      if (idCert == nullptr) {
+        std::cerr << "Error: Cannot load cert-to-publish: " << file << "!" << std::endl;
+        return false;
+      }
 
       m_nlsr.loadCertToPublish(idCert);
     }
+  }
 
   return true;
 }
diff --git a/src/update/prefix-update-processor.cpp b/src/update/prefix-update-processor.cpp
index 12e066a..7b3fe89 100644
--- a/src/update/prefix-update-processor.cpp
+++ b/src/update/prefix-update-processor.cpp
@@ -51,6 +51,7 @@
   , m_sync(sync)
   , m_keyChain(keyChain)
   , m_validator(m_face, broadcastPrefix, certificateCache, certStore)
+  , m_isEnabled(false)
   , COMMAND_PREFIX(ndn::Name(Nlsr::LOCALHOST_PREFIX).append(MODULE_COMPONENT))
 {
 }
@@ -68,6 +69,11 @@
 {
   _LOG_TRACE("Received Interest: " << request);
 
+  if (!m_isEnabled) {
+    sendNack(request);
+    return;
+  }
+
   m_validator.validate(request,
                        bind(&PrefixUpdateProcessor::onCommandValidated, this, _1),
                        bind(&PrefixUpdateProcessor::onCommandValidationFailed, this, _1, _2));
@@ -186,6 +192,19 @@
 }
 
 void
+PrefixUpdateProcessor::sendNack(const ndn::Interest& request)
+{
+  ndn::MetaInfo metaInfo;
+  metaInfo.setType(ndn::tlv::ContentType_Nack);
+
+  shared_ptr<ndn::Data> responseData = std::make_shared<ndn::Data>(request.getName());
+  responseData->setMetaInfo(metaInfo);
+
+  m_keyChain.sign(*responseData);
+  m_face.put(*responseData);
+}
+
+void
 PrefixUpdateProcessor::sendResponse(const std::shared_ptr<const ndn::Interest>& request,
                                     uint32_t code,
                                     const std::string& text)
@@ -197,7 +216,7 @@
   ndn::nfd::ControlResponse response(code, text);
   const ndn::Block& encodedControl = response.wireEncode();
 
-  std::shared_ptr<ndn::Data> responseData = ndn::make_shared<ndn::Data>(request->getName());
+  std::shared_ptr<ndn::Data> responseData = std::make_shared<ndn::Data>(request->getName());
   responseData->setContent(encodedControl);
 
   m_keyChain.sign(*responseData);
diff --git a/src/update/prefix-update-processor.hpp b/src/update/prefix-update-processor.hpp
index 6dc6c09..395d161 100644
--- a/src/update/prefix-update-processor.hpp
+++ b/src/update/prefix-update-processor.hpp
@@ -78,11 +78,20 @@
   void
   startListening();
 
+  void
+  enable()
+  {
+    m_isEnabled = true;
+  }
+
 private:
   void
   onInterest(const ndn::Interest& request);
 
   void
+  sendNack(const ndn::Interest& request);
+
+  void
   sendResponse(const std::shared_ptr<const ndn::Interest>& request,
                uint32_t code,
                const std::string& text);
@@ -128,6 +137,7 @@
   SyncLogicHandler& m_sync;
   ndn::KeyChain& m_keyChain;
   Validator m_validator;
+  bool m_isEnabled;
 
   const ndn::Name COMMAND_PREFIX; // /localhost/nlsr/prefix-update
 
diff --git a/tests/test-conf-file-processor.cpp b/tests/test-conf-file-processor.cpp
index 50cc872..01950d2 100644
--- a/tests/test-conf-file-processor.cpp
+++ b/tests/test-conf-file-processor.cpp
@@ -518,6 +518,23 @@
   boost::filesystem::remove(CERT_PATH);
 }
 
+BOOST_AUTO_TEST_CASE(PrefixUpdateValidatorOptional) // Bug #2814
+{
+  const std::string SECTION_SECURITY =
+  "security\n"
+  "{\n"
+  "  validator\n"
+  "  {\n"
+  "    trust-anchor\n"
+  "    {\n"
+  "      type any\n"
+  "    }\n"
+  "  }\n"
+  "}\n\n";
+
+  BOOST_CHECK(processConfigurationString(SECTION_SECURITY));
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } //namespace test
diff --git a/tests/update/test-prefix-update-processor.cpp b/tests/update/test-prefix-update-processor.cpp
index adb13f4..9a12931 100644
--- a/tests/update/test-prefix-update-processor.cpp
+++ b/tests/update/test-prefix-update-processor.cpp
@@ -27,6 +27,7 @@
 
 #include <ndn-cxx/interest.hpp>
 #include <ndn-cxx/management/nfd-control-parameters.hpp>
+#include <ndn-cxx/management/nfd-control-response.hpp>
 #include <ndn-cxx/security/key-chain.hpp>
 #include <ndn-cxx/util/dummy-client-face.hpp>
 
@@ -167,6 +168,20 @@
     return (it != face->sentDatas.end());
   }
 
+  void
+  checkResponseCode(const Name& commandPrefix, uint64_t expectedCode)
+  {
+    std::vector<Data>::iterator it = std::find_if(face->sentDatas.begin(),
+                                                  face->sentDatas.end(),
+                                                  [commandPrefix] (const Data& data) {
+                                                    return commandPrefix.isPrefixOf(data.getName());
+                                                  });
+    BOOST_REQUIRE(it != face->sentDatas.end());
+
+    ndn::nfd::ControlResponse response(it->getContent().blockFromValue());
+    BOOST_CHECK_EQUAL(response.getCode(), expectedCode);
+  }
+
   ~PrefixUpdateFixture()
   {
     keyChain.deleteIdentity(siteIdentity);
@@ -198,6 +213,8 @@
 
 BOOST_AUTO_TEST_CASE(Basic)
 {
+  updateProcessor.enable();
+
   // Advertise
   ndn::nfd::ControlParameters parameters;
   parameters.setName("/prefix/to/advertise/");
@@ -234,6 +251,38 @@
   BOOST_CHECK(wasRoutingUpdatePublished());
 }
 
+BOOST_AUTO_TEST_CASE(DisabledAndEnabled)
+{
+  ndn::nfd::ControlParameters parameters;
+  parameters.setName("/prefix/to/advertise/");
+
+  ndn::Name advertiseCommand("/localhost/nlsr/prefix-update/advertise");
+  advertiseCommand.append(parameters.wireEncode());
+
+  shared_ptr<Interest> advertiseInterest = make_shared<Interest>(advertiseCommand);
+  keyChain.signByIdentity(*advertiseInterest, opIdentity);
+
+  // Command should be rejected
+  face->receive(*advertiseInterest);
+  face->processEvents(ndn::time::milliseconds(1));
+
+  BOOST_REQUIRE(!face->sentDatas.empty());
+
+  const ndn::MetaInfo& metaInfo = face->sentDatas.front().getMetaInfo();
+  BOOST_CHECK_EQUAL(metaInfo.getType(), ndn::tlv::ContentType_Nack);
+
+  face->sentDatas.clear();
+
+  // Enable PrefixUpdateProcessor so commands will be processed
+  updateProcessor.enable();
+
+  // Command should be accepted
+  face->receive(*advertiseInterest);
+  face->processEvents(ndn::time::milliseconds(1));
+
+  checkResponseCode(advertiseCommand, 200);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace test
diff --git a/tools/nlsrc.cpp b/tools/nlsrc.cpp
index 9142774..fad8fc3 100644
--- a/tools/nlsrc.cpp
+++ b/tools/nlsrc.cpp
@@ -163,6 +163,11 @@
 void
 Nlsrc::onControlResponse(const std::string& info, const ndn::Data& data)
 {
+  if (data.getMetaInfo().getType() == ndn::tlv::ContentType_Nack) {
+    std::cerr << "ERROR: Run-time advertise/withdraw disabled" << std::endl;
+    return;
+  }
+
   ndn::nfd::ControlResponse response;
 
   try {