mgmt: fix Dispatcher::processControlCommandInterest memory error

refs #4059

Change-Id: I6655662f925bc5f40a2a2ec2b258a4accc29d58b
diff --git a/src/mgmt/dispatcher.cpp b/src/mgmt/dispatcher.cpp
index b9d62a2..62f9114 100644
--- a/src/mgmt/dispatcher.cpp
+++ b/src/mgmt/dispatcher.cpp
@@ -218,7 +218,7 @@
     return;
   }
 
-  AcceptContinuation accept = bind(accepted, _1, prefix, interest, parameters.get());
+  AcceptContinuation accept = bind(accepted, _1, prefix, interest, parameters);
   RejectContinuation reject = bind(rejected, _1, interest);
   authorization(prefix, interest, parameters.get(), accept, reject);
 }
@@ -227,7 +227,7 @@
 Dispatcher::processAuthorizedControlCommandInterest(const std::string& requester,
                                                     const Name& prefix,
                                                     const Interest& interest,
-                                                    const ControlParameters* parameters,
+                                                    const shared_ptr<ControlParameters>& parameters,
                                                     const ValidateParameters& validateParams,
                                                     const ControlCommandHandler& handler)
 {
diff --git a/src/mgmt/dispatcher.hpp b/src/mgmt/dispatcher.hpp
index 7df61f7..a8b30b4 100644
--- a/src/mgmt/dispatcher.hpp
+++ b/src/mgmt/dispatcher.hpp
@@ -291,7 +291,7 @@
   typedef std::function<void(const std::string& requester,
                              const Name& prefix,
                              const Interest& interest,
-                             const ControlParameters*)> AuthorizationAcceptedCallback;
+                             const shared_ptr<ControlParameters>&)> AuthorizationAcceptedCallback;
 
   typedef std::function<void(RejectReply act,
                              const Interest& interest)> AuthorizationRejectedCallback;
@@ -399,7 +399,7 @@
   processAuthorizedControlCommandInterest(const std::string& requester,
                                           const Name& prefix,
                                           const Interest& interest,
-                                          const ControlParameters* parameters,
+                                          const shared_ptr<ControlParameters>& parameters,
                                           const ValidateParameters& validate,
                                           const ControlCommandHandler& handler);
 
@@ -484,11 +484,11 @@
                               const ControlCommandHandler& handler)
 {
   if (!m_topLevelPrefixes.empty()) {
-    throw std::domain_error("one or more top-level prefix has been added");
+    BOOST_THROW_EXCEPTION(std::domain_error("one or more top-level prefix has been added"));
   }
 
   if (isOverlappedWithOthers(relPrefix)) {
-    throw std::out_of_range("relPrefix overlaps with another relPrefix");
+    BOOST_THROW_EXCEPTION(std::out_of_range("relPrefix overlaps with another relPrefix"));
   }
 
   ControlParametersParser parser =
diff --git a/tests/unit-tests/mgmt/dispatcher.t.cpp b/tests/unit-tests/mgmt/dispatcher.t.cpp
index a1506a0..96623f5 100644
--- a/tests/unit-tests/mgmt/dispatcher.t.cpp
+++ b/tests/unit-tests/mgmt/dispatcher.t.cpp
@@ -34,9 +34,6 @@
 
 using namespace ndn::tests;
 
-BOOST_AUTO_TEST_SUITE(Mgmt)
-BOOST_AUTO_TEST_SUITE(TestDispatcher)
-
 class DispatcherFixture : public IdentityManagementV1TimeFixture
 {
 public:
@@ -62,17 +59,17 @@
     wireDecode(wire);
   }
 
-  virtual Block
+  Block
   wireEncode() const final
   {
     return Block(128);
   }
 
-  virtual void
+  void
   wireDecode(const Block& wire) final
   {
     if (wire.type() != 128)
-      throw tlv::Error("Expecting TLV type 128");
+      BOOST_THROW_EXCEPTION(tlv::Error("Expecting TLV type 128"));
   }
 };
 
@@ -98,7 +95,10 @@
   };
 }
 
-BOOST_FIXTURE_TEST_CASE(Basic, DispatcherFixture)
+BOOST_AUTO_TEST_SUITE(Mgmt)
+BOOST_FIXTURE_TEST_SUITE(TestDispatcher, DispatcherFixture)
+
+BOOST_AUTO_TEST_CASE(Basic)
 {
   BOOST_CHECK_NO_THROW(dispatcher
                          .addControlCommand<VoidParameters>("test/1", makeAcceptAllAuthorization(),
@@ -145,7 +145,7 @@
   BOOST_CHECK_THROW(dispatcher.addNotificationStream("stream/3"), std::domain_error);
 }
 
-BOOST_FIXTURE_TEST_CASE(AddRemoveTopPrefix, DispatcherFixture)
+BOOST_AUTO_TEST_CASE(AddRemoveTopPrefix)
 {
   std::map<std::string, size_t> nCallbackCalled;
   dispatcher
@@ -205,7 +205,7 @@
   BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 4);
 }
 
-BOOST_FIXTURE_TEST_CASE(ControlCommand, DispatcherFixture)
+BOOST_AUTO_TEST_CASE(ControlCommand)
 {
   size_t nCallbackCalled = 0;
   dispatcher
@@ -237,7 +237,73 @@
   BOOST_CHECK_EQUAL(nCallbackCalled, 1);
 }
 
-BOOST_FIXTURE_TEST_CASE(StatusDataset, DispatcherFixture)
+class StatefulParameters : public mgmt::ControlParameters
+{
+public:
+  explicit
+  StatefulParameters(const Block& wire)
+  {
+    wireDecode(wire);
+  }
+
+  Block
+  wireEncode() const final
+  {
+    return Block();
+  }
+
+  void
+  wireDecode(const Block& wire) final
+  {
+    m_state = EXPECTED_STATE;
+  }
+
+  bool
+  check() const
+  {
+    return m_state == EXPECTED_STATE;
+  }
+
+private:
+  static constexpr int EXPECTED_STATE = 12602;
+  int m_state = 0;
+};
+
+BOOST_AUTO_TEST_CASE(ControlCommandAsyncAuthorization) // Bug 4059
+{
+  AcceptContinuation authorizationAccept;
+  auto authorization =
+    [&authorizationAccept] (const Name& prefix, const Interest& interest, const ControlParameters* params,
+        AcceptContinuation accept, RejectContinuation reject) {
+      authorizationAccept = accept;
+    };
+
+  auto validateParameters =
+    [] (const ControlParameters& params) {
+      return dynamic_cast<const StatefulParameters&>(params).check();
+    };
+
+  size_t nCallbackCalled = 0;
+  dispatcher
+    .addControlCommand<StatefulParameters>("test",
+                                           authorization,
+                                           validateParameters,
+                                           bind([&nCallbackCalled] { ++nCallbackCalled; }));
+
+  dispatcher.addTopPrefix("/root");
+  advanceClocks(time::milliseconds(1));
+
+  face.receive(*makeInterest("/root/test/%80%00"));
+  BOOST_CHECK_EQUAL(nCallbackCalled, 0);
+  BOOST_REQUIRE(authorizationAccept != nullptr);
+
+  advanceClocks(time::milliseconds(1));
+  authorizationAccept("");
+  advanceClocks(time::milliseconds(1));
+  BOOST_CHECK_EQUAL(nCallbackCalled, 1);
+}
+
+BOOST_AUTO_TEST_CASE(StatusDataset)
 {
   static Block smallBlock("\x81\x01\0x01", 3);
   static Block largeBlock = [] () -> Block {
@@ -369,7 +435,7 @@
   BOOST_CHECK_EQUAL(storage.size(), 0); // the nack packet will not be inserted into the in-memory storage
 }
 
-BOOST_FIXTURE_TEST_CASE(NotificationStream, DispatcherFixture)
+BOOST_AUTO_TEST_CASE(NotificationStream)
 {
   static Block block("\x82\x01\x02", 3);