mgmt: Controller cleans up fetchers on destruction

refs: #4775

Change-Id: I795b1ee273d0cca6df23be6c87255fc6d33b3651
diff --git a/src/mgmt/nfd/controller.cpp b/src/mgmt/nfd/controller.cpp
index 1af70b7..05570fd 100644
--- a/src/mgmt/nfd/controller.cpp
+++ b/src/mgmt/nfd/controller.cpp
@@ -22,7 +22,6 @@
 #include "controller.hpp"
 #include "face.hpp"
 #include "security/v2/key-chain.hpp"
-#include "util/segment-fetcher.hpp"
 
 #include <boost/lexical_cast.hpp>
 
@@ -45,6 +44,13 @@
 {
 }
 
+Controller::~Controller()
+{
+  for (const auto& sp : m_fetchers) {
+    sp->stop();
+  }
+}
+
 void
 Controller::startCommand(const shared_ptr<ControlCommand>& command,
                          const ControlParameters& parameters,
@@ -151,6 +157,10 @@
       processDatasetFetchError(onFailure, code, msg);
     });
   }
+
+  auto it = m_fetchers.insert(fetcher).first;
+  fetcher->onComplete.connect([this, it] (ConstBufferPtr) { m_fetchers.erase(it); });
+  fetcher->onError.connect([this, it] (uint32_t, const std::string&) { m_fetchers.erase(it); });
 }
 
 void
diff --git a/src/mgmt/nfd/controller.hpp b/src/mgmt/nfd/controller.hpp
index 0553df1..422e7b7 100644
--- a/src/mgmt/nfd/controller.hpp
+++ b/src/mgmt/nfd/controller.hpp
@@ -30,6 +30,7 @@
 #include "../../security/validator-null.hpp"
 #include "../../security/v2/key-chain.hpp"
 #include "../../security/v2/validator.hpp"
+#include "../../util/segment-fetcher.hpp"
 
 namespace ndn {
 
@@ -68,6 +69,8 @@
   Controller(Face& face, KeyChain& keyChain,
              security::v2::Validator& validator = security::getAcceptAllValidator());
 
+  ~Controller();
+
   /** \brief start command execution
    */
   template<typename Command>
@@ -172,6 +175,9 @@
   KeyChain& m_keyChain;
   security::v2::Validator& m_validator;
   security::CommandInterestSigner m_signer;
+
+NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PROTECTED:
+  std::set<shared_ptr<util::SegmentFetcher>> m_fetchers;
 };
 
 template<typename Dataset>
diff --git a/tests/unit-tests/mgmt/nfd/status-dataset.t.cpp b/tests/unit-tests/mgmt/nfd/status-dataset.t.cpp
index 12a7fa1..a436de0 100644
--- a/tests/unit-tests/mgmt/nfd/status-dataset.t.cpp
+++ b/tests/unit-tests/mgmt/nfd/status-dataset.t.cpp
@@ -115,8 +115,11 @@
     [] (const std::vector<FaceStatus>& result) { BOOST_FAIL("fetchDataset should not succeed"); },
     datasetFailCallback,
     options);
-  this->advanceClocks(500_ms, 7);
+  this->advanceClocks(500_ms);
+  BOOST_CHECK_EQUAL(controller.m_fetchers.size(), 1);
 
+  this->advanceClocks(500_ms, 6);
+  BOOST_CHECK_EQUAL(controller.m_fetchers.size(), 0);
   BOOST_REQUIRE_EQUAL(failCodes.size(), 1);
   BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_TIMEOUT);
 }
@@ -210,6 +213,7 @@
     nullptr,
     datasetFailCallback);
   this->advanceClocks(500_ms);
+  BOOST_CHECK_EQUAL(controller.m_fetchers.size(), 1);
 
   FaceStatus payload;
   payload.setFaceId(2577);
@@ -217,6 +221,7 @@
   BOOST_CHECK_NO_THROW(this->advanceClocks(500_ms));
 
   BOOST_CHECK_EQUAL(failCodes.size(), 0);
+  BOOST_CHECK_EQUAL(controller.m_fetchers.size(), 0);
 }
 
 BOOST_AUTO_TEST_CASE(Failure)