face: replace EventEmitter usage with Signal

refs #2300

Change-Id: I17d0d65d2c474b17dd9f23f271a6144b0b4fbc07
diff --git a/daemon/face/datagram-face.hpp b/daemon/face/datagram-face.hpp
index 5b1b3d9..f0ad2b4 100644
--- a/daemon/face/datagram-face.hpp
+++ b/daemon/face/datagram-face.hpp
@@ -129,7 +129,7 @@
 inline void
 DatagramFace<T, U>::sendInterest(const Interest& interest)
 {
-  this->onSendInterest(interest);
+  this->emitSignal(onSendInterest, interest);
   const Block& payload = interest.wireEncode();
   m_socket->async_send(boost::asio::buffer(payload.wire(), payload.size()),
                        bind(&DatagramFace<T, U>::handleSend, this, _1, _2, payload));
@@ -141,7 +141,7 @@
 inline void
 DatagramFace<T, U>::sendData(const Data& data)
 {
-  this->onSendData(data);
+  this->emitSignal(onSendData, data);
   const Block& payload = data.wireEncode();
   m_socket->async_send(boost::asio::buffer(payload.wire(), payload.size()),
                        bind(&DatagramFace<T, U>::handleSend, this, _1, _2, payload));
@@ -176,8 +176,7 @@
       fail("Tunnel closed");
     }
     else {
-      fail("Send operation failed, closing socket: " +
-             error.category().message(error.value()));
+      fail("Send operation failed, closing socket: " + error.message());
     }
     return;
   }
diff --git a/daemon/face/ethernet-face.cpp b/daemon/face/ethernet-face.cpp
index c63e38e..f1fd7c3 100644
--- a/daemon/face/ethernet-face.cpp
+++ b/daemon/face/ethernet-face.cpp
@@ -123,7 +123,7 @@
 void
 EthernetFace::sendInterest(const Interest& interest)
 {
-  onSendInterest(interest);
+  this->emitSignal(onSendInterest, interest);
   ndnlp::PacketArray pa = m_slicer->slice(interest.wireEncode());
   for (const auto& packet : *pa) {
     sendPacket(packet);
@@ -133,7 +133,7 @@
 void
 EthernetFace::sendData(const Data& data)
 {
-  onSendData(data);
+  this->emitSignal(onSendData, data);
   ndnlp::PacketArray pa = m_slicer->slice(data.wireEncode());
   for (const auto& packet : *pa) {
     sendPacket(packet);
@@ -387,7 +387,7 @@
     {
       // new sender, setup a PartialMessageStore for it
       reassembler.pms.reset(new ndnlp::PartialMessageStore);
-      reassembler.pms->onReceive +=
+      reassembler.pms->onReceive.connect(
         [this, sourceAddress] (const Block& block) {
           NFD_LOG_TRACE("[id:" << getId() << ",endpoint:" << m_interfaceName
                         << "] All fragments received from " << sourceAddress.toString());
@@ -395,7 +395,7 @@
             NFD_LOG_WARN("[id:" << getId() << ",endpoint:" << m_interfaceName
                          << "] Received unrecognized TLV block of type " << block.type()
                          << " from " << sourceAddress.toString());
-        };
+        });
     }
 
   scheduler::cancel(reassembler.expireEvent);
diff --git a/daemon/face/ethernet-factory.cpp b/daemon/face/ethernet-factory.cpp
index a4579f4..d07efa4 100644
--- a/daemon/face/ethernet-factory.cpp
+++ b/daemon/face/ethernet-factory.cpp
@@ -48,9 +48,9 @@
   face = make_shared<EthernetFace>(socket, interface, address);
 
   auto key = std::make_pair(interface.name, address);
-  face->onFail += [this, key] (const std::string& reason) {
+  face->onFail.connectSingleShot([this, key] (const std::string& reason) {
     m_multicastFaces.erase(key);
-  };
+  });
   m_multicastFaces.insert({key, face});
 
   return face;
diff --git a/daemon/face/face.cpp b/daemon/face/face.cpp
index 7d3c1b7..0adf2ed 100644
--- a/daemon/face/face.cpp
+++ b/daemon/face/face.cpp
@@ -36,10 +36,10 @@
   , m_isOnDemand(false)
   , m_isFailed(false)
 {
-  onReceiveInterest += [this](const ndn::Interest&) { ++m_counters.getNInInterests(); };
-  onReceiveData     += [this](const ndn::Data&) {     ++m_counters.getNInDatas(); };
-  onSendInterest    += [this](const ndn::Interest&) { ++m_counters.getNOutInterests(); };
-  onSendData        += [this](const ndn::Data&) {     ++m_counters.getNOutDatas(); };
+  onReceiveInterest.connect([this] (const ndn::Interest&) { ++m_counters.getNInInterests(); });
+  onReceiveData    .connect([this] (const ndn::Data&)     { ++m_counters.getNInDatas(); });
+  onSendInterest   .connect([this] (const ndn::Interest&) { ++m_counters.getNOutInterests(); });
+  onSendData       .connect([this] (const ndn::Data&)     { ++m_counters.getNOutDatas(); });
 }
 
 Face::~Face()
@@ -120,8 +120,6 @@
 
   m_isFailed = true;
   this->onFail(reason);
-
-  this->onFail.clear();
 }
 
 template<typename FaceTraits>
diff --git a/daemon/face/face.hpp b/daemon/face/face.hpp
index 40a77a1..156a82d 100644
--- a/daemon/face/face.hpp
+++ b/daemon/face/face.hpp
@@ -78,19 +78,19 @@
   ~Face();
 
   /// fires when an Interest is received
-  EventEmitter<Interest> onReceiveInterest;
+  signal::Signal<Face, Interest> onReceiveInterest;
 
   /// fires when a Data is received
-  EventEmitter<Data> onReceiveData;
+  signal::Signal<Face, Data> onReceiveData;
 
   /// fires when an Interest is sent out
-  EventEmitter<Interest> onSendInterest;
+  signal::Signal<Face, Interest> onSendInterest;
 
   /// fires when a Data is sent out
-  EventEmitter<Data> onSendData;
+  signal::Signal<Face, Data> onSendData;
 
   /// fires when face disconnects or fails to perform properly
-  EventEmitter<std::string/*reason*/> onFail;
+  signal::Signal<Face, std::string/*reason*/> onFail;
 
   /// send an Interest
   virtual void
@@ -187,6 +187,11 @@
   void
   fail(const std::string& reason);
 
+  DECLARE_SIGNAL_EMIT(onReceiveInterest)
+  DECLARE_SIGNAL_EMIT(onReceiveData)
+  DECLARE_SIGNAL_EMIT(onSendInterest)
+  DECLARE_SIGNAL_EMIT(onSendData)
+
 private:
   void
   setId(FaceId faceId);
diff --git a/daemon/face/local-face.hpp b/daemon/face/local-face.hpp
index e1c34c3..c190956 100644
--- a/daemon/face/local-face.hpp
+++ b/daemon/face/local-face.hpp
@@ -156,7 +156,7 @@
               this->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID));
           }
 
-        this->onReceiveInterest(*i);
+        this->emitSignal(onReceiveInterest, *i);
       }
     else if (payload.type() == tlv::Data)
       {
@@ -174,7 +174,7 @@
         //       false);
         //   }
 
-        this->onReceiveData(*d);
+        this->emitSignal(onReceiveData, *d);
       }
     else
       return false;
diff --git a/daemon/face/multicast-udp-face.cpp b/daemon/face/multicast-udp-face.cpp
index 34c6cd2..7e91ca5 100644
--- a/daemon/face/multicast-udp-face.cpp
+++ b/daemon/face/multicast-udp-face.cpp
@@ -61,7 +61,7 @@
 void
 MulticastUdpFace::sendInterest(const Interest& interest)
 {
-  onSendInterest(interest);
+  this->emitSignal(onSendInterest, interest);
 
   NFD_LOG_DEBUG("Sending interest");
   sendBlock(interest.wireEncode());
@@ -70,9 +70,9 @@
 void
 MulticastUdpFace::sendData(const Data& data)
 {
-  /// \todo After this method implements duplicate suppression, onSendData event should
-  ///       be triggered only when data is actually sent out
-  onSendData(data);
+  /// \todo After this method implements duplicate suppression, onSendData signal should
+  ///       be emitted only when data is actually sent out
+  this->emitSignal(onSendData, data);
 
   NFD_LOG_DEBUG("Sending data");
   sendBlock(data.wireEncode());
diff --git a/daemon/face/ndnlp-partial-message-store.hpp b/daemon/face/ndnlp-partial-message-store.hpp
index c707d92..1aed1e0 100644
--- a/daemon/face/ndnlp-partial-message-store.hpp
+++ b/daemon/face/ndnlp-partial-message-store.hpp
@@ -1,11 +1,12 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014  Regents of the University of California,
- *                     Arizona Board of Regents,
- *                     Colorado State University,
- *                     University Pierre & Marie Curie, Sorbonne University,
- *                     Washington University in St. Louis,
- *                     Beijing Institute of Technology
+ * Copyright (c) 2014,  Regents of the University of California,
+ *                      Arizona Board of Regents,
+ *                      Colorado State University,
+ *                      University Pierre & Marie Curie, Sorbonne University,
+ *                      Washington University in St. Louis,
+ *                      Beijing Institute of Technology,
+ *                      The University of Memphis
  *
  * This file is part of NFD (Named Data Networking Forwarding Daemon).
  * See AUTHORS.md for complete list of NFD authors and contributors.
@@ -20,7 +21,7 @@
  *
  * You should have received a copy of the GNU General Public License along with
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- **/
+ */
 
 #ifndef NFD_DAEMON_FACE_NDNLP_PARTIAL_MESSAGE_STORE_HPP
 #define NFD_DAEMON_FACE_NDNLP_PARTIAL_MESSAGE_STORE_HPP
@@ -84,7 +85,7 @@
   receiveNdnlpData(const Block& pkt);
 
   /// fires when network layer packet is received
-  EventEmitter<Block> onReceive;
+  signal::Signal<PartialMessageStore, Block> onReceive;
 
 private:
   void
diff --git a/daemon/face/stream-face.hpp b/daemon/face/stream-face.hpp
index e719da3..e7cf894 100644
--- a/daemon/face/stream-face.hpp
+++ b/daemon/face/stream-face.hpp
@@ -178,7 +178,7 @@
 inline void
 StreamFace<T, U>::sendInterest(const Interest& interest)
 {
-  this->onSendInterest(interest);
+  this->emitSignal(onSendInterest, interest);
   StreamFaceSenderImpl<T, U, Interest>::send(*this, interest);
 }
 
@@ -186,7 +186,7 @@
 inline void
 StreamFace<T, U>::sendData(const Data& data)
 {
-  this->onSendData(data);
+  this->emitSignal(onSendData, data);
   StreamFaceSenderImpl<T, U, Data>::send(*this, data);
 }
 
diff --git a/daemon/face/tcp-channel.cpp b/daemon/face/tcp-channel.cpp
index cd2744d..01eb07a 100644
--- a/daemon/face/tcp-channel.cpp
+++ b/daemon/face/tcp-channel.cpp
@@ -140,7 +140,7 @@
       else
         face = make_shared<TcpFace>(socket, isOnDemand);
 
-      face->onFail += bind(&TcpChannel::afterFaceFailed, this, remoteEndpoint);
+      face->onFail.connectSingleShot(bind(&TcpChannel::afterFaceFailed, this, remoteEndpoint));
 
       m_channelFaces[remoteEndpoint] = face;
     }
diff --git a/daemon/face/udp-channel.cpp b/daemon/face/udp-channel.cpp
index 2ab4b77..83bb607 100644
--- a/daemon/face/udp-channel.cpp
+++ b/daemon/face/udp-channel.cpp
@@ -177,7 +177,8 @@
   if (faceMapPos == m_channelFaces.end())
     {
       face = make_shared<UdpFace>(socket, isOnDemand, m_idleFaceTimeout);
-      face->onFail += bind(&UdpChannel::afterFaceFailed, this, remoteEndpoint);
+
+      face->onFail.connectSingleShot(bind(&UdpChannel::afterFaceFailed, this, remoteEndpoint));
 
       m_channelFaces[remoteEndpoint] = face;
     }
diff --git a/daemon/face/udp-face.cpp b/daemon/face/udp-face.cpp
index 81e915c..400e7dc 100644
--- a/daemon/face/udp-face.cpp
+++ b/daemon/face/udp-face.cpp
@@ -24,6 +24,7 @@
  */
 
 #include "udp-face.hpp"
+// #include "core/global-io.hpp" // for #1718 manual test below
 
 #ifdef __linux__
 #include <netinet/in.h> // for IP_MTU_DISCOVER and IP_PMTUDISC_DONT
@@ -112,6 +113,12 @@
                    << ",uri:" << this->getRemoteUri()
                    << "] Idle for more than " << m_idleTimeout << ", closing");
       close();
+
+      // #1718 manual test: uncomment, run NFD in valgrind, send in a UDP packet
+      //                    expect read-after-free error and crash
+      // getGlobalIoService().post([this] {
+      //   NFD_LOG_ERROR("Remaining references: " << this->shared_from_this().use_count());
+      // });
     }
     else {
       resetRecentUsage();
diff --git a/daemon/face/udp-factory.cpp b/daemon/face/udp-factory.cpp
index 458d4fb..40d1788 100644
--- a/daemon/face/udp-factory.cpp
+++ b/daemon/face/udp-factory.cpp
@@ -237,7 +237,8 @@
 
   multicastFace = make_shared<MulticastUdpFace>(receiveSocket, sendSocket,
                                                 localEndpoint, multicastEndpoint);
-  multicastFace->onFail += bind(&UdpFactory::afterFaceFailed, this, localEndpoint);
+
+  multicastFace->onFail.connectSingleShot(bind(&UdpFactory::afterFaceFailed, this, localEndpoint));
 
   m_multicastFaces[localEndpoint] = multicastFace;
 
diff --git a/daemon/face/websocket-face.cpp b/daemon/face/websocket-face.cpp
index abd8b3c..ad344d1 100644
--- a/daemon/face/websocket-face.cpp
+++ b/daemon/face/websocket-face.cpp
@@ -47,7 +47,7 @@
   if (m_closed)
     return;
 
-  this->onSendInterest(interest);
+  this->emitSignal(onSendInterest, interest);
   const Block& payload = interest.wireEncode();
   this->getMutableCounters().getNOutBytes() += payload.size();
 
@@ -67,7 +67,7 @@
   if (m_closed)
     return;
 
-  this->onSendData(data);
+  this->emitSignal(onSendData, data);
   const Block& payload = data.wireEncode();
   this->getMutableCounters().getNOutBytes() += payload.size();
 
diff --git a/daemon/fw/face-table.cpp b/daemon/fw/face-table.cpp
index f1db53b..71a7cf6 100644
--- a/daemon/fw/face-table.cpp
+++ b/daemon/fw/face-table.cpp
@@ -85,12 +85,9 @@
   NFD_LOG_INFO("Added face id=" << faceId << " remote=" << face->getRemoteUri()
                                           << " local=" << face->getLocalUri());
 
-  face->onReceiveInterest += bind(&Forwarder::onInterest,
-                                  &m_forwarder, ref(*face), _1);
-  face->onReceiveData     += bind(&Forwarder::onData,
-                                  &m_forwarder, ref(*face), _1);
-  face->onFail            += bind(&FaceTable::remove,
-                                  this, face);
+  face->onReceiveInterest.connect(bind(&Forwarder::onInterest, &m_forwarder, ref(*face), _1));
+  face->onReceiveData.connect(bind(&Forwarder::onData, &m_forwarder, ref(*face), _1));
+  face->onFail.connectSingleShot(bind(&FaceTable::remove, this, face));
 
   this->onAdd(face);
 }
@@ -104,15 +101,7 @@
   m_faces.erase(faceId);
   face->setId(INVALID_FACEID);
   NFD_LOG_INFO("Removed face id=" << faceId << " remote=" << face->getRemoteUri() <<
-                                                 " local=" << face->getLocalUri());
-
-  // XXX This clears all subscriptions, because EventEmitter
-  //     does not support only removing Forwarder's subscription
-  face->onReceiveInterest.clear();
-  face->onReceiveData    .clear();
-  face->onSendInterest   .clear();
-  face->onSendData       .clear();
-  // don't clear onFail because other functions may need to execute
+                                                " local=" << face->getLocalUri());
 
   m_forwarder.getFib().removeNextHopFromAllEntries(face);
 }
diff --git a/daemon/mgmt/internal-face.cpp b/daemon/mgmt/internal-face.cpp
index 9fad328..d33282e 100644
--- a/daemon/mgmt/internal-face.cpp
+++ b/daemon/mgmt/internal-face.cpp
@@ -39,7 +39,7 @@
 void
 InternalFace::sendInterest(const Interest& interest)
 {
-  onSendInterest(interest);
+  this->emitSignal(onSendInterest, interest);
 
   // Invoke .processInterest a bit later,
   // to avoid potential problems in forwarding pipelines.
@@ -122,7 +122,7 @@
 void
 InternalFace::sendData(const Data& data)
 {
-  onSendData(data);
+  this->emitSignal(onSendData, data);
 }
 
 void
@@ -142,7 +142,7 @@
 void
 InternalFace::put(const Data& data)
 {
-  onReceiveData(data);
+  this->emitSignal(onReceiveData, data);
 }
 
 InternalFace::~InternalFace()
diff --git a/tests/daemon/face/dummy-face.hpp b/tests/daemon/face/dummy-face.hpp
index ec0adbf..dc9bcc6 100644
--- a/tests/daemon/face/dummy-face.hpp
+++ b/tests/daemon/face/dummy-face.hpp
@@ -52,7 +52,7 @@
   virtual void
   sendInterest(const Interest& interest)
   {
-    this->onSendInterest(interest);
+    this->emitSignal(onSendInterest, interest);
     m_sentInterests.push_back(interest);
     this->afterSend();
   }
@@ -60,7 +60,7 @@
   virtual void
   sendData(const Data& data)
   {
-    this->onSendData(data);
+    this->emitSignal(onSendData, data);
     m_sentDatas.push_back(data);
     this->afterSend();
   }
@@ -68,22 +68,22 @@
   virtual void
   close()
   {
-    this->onFail("close");
+    this->fail("close");
   }
 
   void
   receiveInterest(const Interest& interest)
   {
-    this->onReceiveInterest(interest);
+    this->emitSignal(onReceiveInterest, interest);
   }
 
   void
   receiveData(const Data& data)
   {
-    this->onReceiveData(data);
+    this->emitSignal(onReceiveData, data);
   }
 
-  EventEmitter<> afterSend;
+  signal::Signal<DummyFaceImpl<FaceBase>> afterSend;
 
 public:
   std::vector<Interest> m_sentInterests;
diff --git a/tests/daemon/face/ethernet.cpp b/tests/daemon/face/ethernet.cpp
index ab0181c..50f403a 100644
--- a/tests/daemon/face/ethernet.cpp
+++ b/tests/daemon/face/ethernet.cpp
@@ -121,7 +121,7 @@
   BOOST_CHECK_EQUAL(face->getCounters().getNInBytes(), 0);
   BOOST_CHECK_EQUAL(face->getCounters().getNOutBytes(), 0);
 
-  face->onFail += [] (const std::string& reason) { BOOST_FAIL(reason); };
+  face->onFail.connect([] (const std::string& reason) { BOOST_FAIL(reason); });
 
   shared_ptr<Interest> interest1 = makeInterest("ndn:/TpnzGvW9R");
   shared_ptr<Data>     data1     = makeData("ndn:/KfczhUqVix");
@@ -171,9 +171,10 @@
   std::vector<Interest> recInterests;
   std::vector<Data>     recDatas;
 
-  face->onFail            += [] (const std::string& reason) { BOOST_FAIL(reason); };
-  face->onReceiveInterest += [&recInterests] (const Interest& i) { recInterests.push_back(i); };
-  face->onReceiveData     += [&recDatas]     (const Data& d)     { recDatas.push_back(d);     };
+  face->onFail.connect([] (const std::string& reason) { BOOST_FAIL(reason); });
+  face->onReceiveInterest.connect(
+      [&recInterests] (const Interest& i) { recInterests.push_back(i); });
+  face->onReceiveData.connect([&recDatas] (const Data& d) { recDatas.push_back(d); });
 
   // check that packet data is not accessed if pcap didn't capture anything (caplen == 0)
   static const pcap_pkthdr header1{};
diff --git a/tests/daemon/face/face.cpp b/tests/daemon/face/face.cpp
index 143dfe6..a8f397a 100644
--- a/tests/daemon/face/face.cpp
+++ b/tests/daemon/face/face.cpp
@@ -65,7 +65,7 @@
   FaceFailTestFace()
     : failCount(0)
   {
-    this->onFail += bind(&FaceFailTestFace::failHandler, this, _1);
+    this->onFail.connect(bind(&FaceFailTestFace::failHandler, this, _1));
   }
 
   void
diff --git a/tests/daemon/face/ndnlp.cpp b/tests/daemon/face/ndnlp.cpp
index f5ba8e1..89f72b0 100644
--- a/tests/daemon/face/ndnlp.cpp
+++ b/tests/daemon/face/ndnlp.cpp
@@ -1,11 +1,12 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014  Regents of the University of California,
- *                     Arizona Board of Regents,
- *                     Colorado State University,
- *                     University Pierre & Marie Curie, Sorbonne University,
- *                     Washington University in St. Louis,
- *                     Beijing Institute of Technology
+ * Copyright (c) 2014,  Regents of the University of California,
+ *                      Arizona Board of Regents,
+ *                      Colorado State University,
+ *                      University Pierre & Marie Curie, Sorbonne University,
+ *                      Washington University in St. Louis,
+ *                      Beijing Institute of Technology,
+ *                      The University of Memphis
  *
  * This file is part of NFD (Named Data Networking Forwarding Daemon).
  * See AUTHORS.md for complete list of NFD authors and contributors.
@@ -20,7 +21,7 @@
  *
  * You should have received a copy of the GNU General Public License along with
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- **/
+ */
 
 #include "face/ndnlp-sequence-generator.hpp"
 #include "face/ndnlp-slicer.hpp"
@@ -156,10 +157,9 @@
   ReassembleFixture()
     : m_slicer(1500)
   {
-    m_partialMessageStore.onReceive +=
-      // push_back in C++11 has 2 overloads, and specific version needs to be selected
-      bind(static_cast<void (std::vector<Block>::*)(const Block&)>(&std::vector<Block>::push_back),
-           &m_received, _1);
+    m_partialMessageStore.onReceive.connect([this] (const Block& block) {
+      m_received.push_back(block);
+    });
   }
 
   Block
diff --git a/tests/daemon/face/tcp.cpp b/tests/daemon/face/tcp.cpp
index 7c8e33b..ec7f54f 100644
--- a/tests/daemon/face/tcp.cpp
+++ b/tests/daemon/face/tcp.cpp
@@ -119,12 +119,9 @@
   {
     BOOST_CHECK(!static_cast<bool>(face1));
     face1 = newFace;
-    face1->onReceiveInterest +=
-      bind(&EndToEndFixture::face1_onReceiveInterest, this, _1);
-    face1->onReceiveData +=
-      bind(&EndToEndFixture::face1_onReceiveData, this, _1);
-    face1->onFail +=
-      bind(&EndToEndFixture::face1_onFail, this);
+    face1->onReceiveInterest.connect(bind(&EndToEndFixture::face1_onReceiveInterest, this, _1));
+    face1->onReceiveData.connect(bind(&EndToEndFixture::face1_onReceiveData, this, _1));
+    face1->onFail.connect(bind(&EndToEndFixture::face1_onFail, this));
 
     limitedIo.afterOp();
   }
@@ -165,12 +162,9 @@
   {
     BOOST_CHECK(!static_cast<bool>(face2));
     face2 = newFace;
-    face2->onReceiveInterest +=
-      bind(&EndToEndFixture::face2_onReceiveInterest, this, _1);
-    face2->onReceiveData +=
-      bind(&EndToEndFixture::face2_onReceiveData, this, _1);
-    face2->onFail +=
-      bind(&EndToEndFixture::face2_onFail, this);
+    face2->onReceiveInterest.connect(bind(&EndToEndFixture::face2_onReceiveInterest, this, _1));
+    face2->onReceiveData.connect(bind(&EndToEndFixture::face2_onReceiveData, this, _1));
+    face2->onFail.connect(bind(&EndToEndFixture::face2_onFail, this));
 
     limitedIo.afterOp();
   }
@@ -492,12 +486,9 @@
   void
   onFaceCreated(const shared_ptr<Face>& face)
   {
-    face->onReceiveInterest +=
-      bind(&SimpleEndToEndFixture::onReceiveInterest, this, _1);
-    face->onReceiveData +=
-      bind(&SimpleEndToEndFixture::onReceiveData, this, _1);
-    face->onFail +=
-      bind(&SimpleEndToEndFixture::onFail, this, face);
+    face->onReceiveInterest.connect(bind(&SimpleEndToEndFixture::onReceiveInterest, this, _1));
+    face->onReceiveData.connect(bind(&SimpleEndToEndFixture::onReceiveData, this, _1));
+    face->onFail.connect(bind(&SimpleEndToEndFixture::onFail, this, face));
 
     if (static_cast<bool>(dynamic_pointer_cast<LocalFace>(face))) {
       static_pointer_cast<LocalFace>(face)->setLocalControlHeaderFeature(
diff --git a/tests/daemon/face/udp.cpp b/tests/daemon/face/udp.cpp
index abab320..24a4bb8 100644
--- a/tests/daemon/face/udp.cpp
+++ b/tests/daemon/face/udp.cpp
@@ -259,12 +259,9 @@
   channel1_onFaceCreatedNoCheck(const shared_ptr<Face>& newFace)
   {
     face1 = newFace;
-    face1->onReceiveInterest +=
-      bind(&EndToEndFixture::face1_onReceiveInterest, this, _1);
-    face1->onReceiveData +=
-      bind(&EndToEndFixture::face1_onReceiveData, this, _1);
-    face1->onFail +=
-      bind(&EndToEndFixture::face1_onFail, this);
+    face1->onReceiveInterest.connect(bind(&EndToEndFixture::face1_onReceiveInterest, this, _1));
+    face1->onReceiveData.connect(bind(&EndToEndFixture::face1_onReceiveData, this, _1));
+    face1->onFail.connect(bind(&EndToEndFixture::face1_onFail, this));
     BOOST_CHECK_MESSAGE(true, "channel 1 face created");
 
     faces.push_back(face1);
@@ -308,12 +305,9 @@
   {
     BOOST_CHECK(!static_cast<bool>(face2));
     face2 = newFace;
-    face2->onReceiveInterest +=
-      bind(&EndToEndFixture::face2_onReceiveInterest, this, _1);
-    face2->onReceiveData +=
-      bind(&EndToEndFixture::face2_onReceiveData, this, _1);
-    face2->onFail +=
-      bind(&EndToEndFixture::face2_onFail, this);
+    face2->onReceiveInterest.connect(bind(&EndToEndFixture::face2_onReceiveInterest, this, _1));
+    face2->onReceiveData.connect(bind(&EndToEndFixture::face2_onReceiveData, this, _1));
+    face2->onFail.connect(bind(&EndToEndFixture::face2_onFail, this));
 
     faces.push_back(face2);
 
diff --git a/tests/daemon/face/unix-stream.cpp b/tests/daemon/face/unix-stream.cpp
index 24154ec..9bbacb3 100644
--- a/tests/daemon/face/unix-stream.cpp
+++ b/tests/daemon/face/unix-stream.cpp
@@ -96,10 +96,8 @@
   {
     BOOST_CHECK(!static_cast<bool>(face1));
     face1 = static_pointer_cast<UnixStreamFace>(newFace);
-    face1->onReceiveInterest +=
-      bind(&EndToEndFixture::face1_onReceiveInterest, this, _1);
-    face1->onReceiveData +=
-      bind(&EndToEndFixture::face1_onReceiveData, this, _1);
+    face1->onReceiveInterest.connect(bind(&EndToEndFixture::face1_onReceiveInterest, this, _1));
+    face1->onReceiveData.connect(bind(&EndToEndFixture::face1_onReceiveData, this, _1));
 
     limitedIo.afterOp();
   }
@@ -199,10 +197,8 @@
                     face1localUri.size() - std::string(CHANNEL_PATH1).size());
 
   face2 = make_shared<UnixStreamFace>(client);
-  face2->onReceiveInterest +=
-    bind(&EndToEndFixture::face2_onReceiveInterest, this, _1);
-  face2->onReceiveData +=
-    bind(&EndToEndFixture::face2_onReceiveData, this, _1);
+  face2->onReceiveInterest.connect(bind(&EndToEndFixture::face2_onReceiveInterest, this, _1));
+  face2->onReceiveData.connect(bind(&EndToEndFixture::face2_onReceiveData, this, _1));
 
   shared_ptr<Interest> interest1 = makeInterest("ndn:/TpnzGvW9R");
   shared_ptr<Data>     data1     = makeData("ndn:/KfczhUqVix");
@@ -282,12 +278,12 @@
 
   // we should still be able to send/receive with the other one
   face1 = faces.back();
-  face1->onReceiveInterest += bind(&EndToEndFixture::face1_onReceiveInterest, this, _1);
-  face1->onReceiveData += bind(&EndToEndFixture::face1_onReceiveData, this, _1);
+  face1->onReceiveInterest.connect(bind(&EndToEndFixture::face1_onReceiveInterest, this, _1));
+  face1->onReceiveData.connect(bind(&EndToEndFixture::face1_onReceiveData, this, _1));
 
   face2 = make_shared<UnixStreamFace>(client2);
-  face2->onReceiveInterest += bind(&EndToEndFixture::face2_onReceiveInterest, this, _1);
-  face2->onReceiveData += bind(&EndToEndFixture::face2_onReceiveData, this, _1);
+  face2->onReceiveInterest.connect(bind(&EndToEndFixture::face2_onReceiveInterest, this, _1));
+  face2->onReceiveData.connect(bind(&EndToEndFixture::face2_onReceiveData, this, _1));
 
   shared_ptr<Interest> interest1 = makeInterest("ndn:/TpnzGvW9R");
   shared_ptr<Data>     data1     = makeData("ndn:/KfczhUqVix");
@@ -336,10 +332,8 @@
   BOOST_REQUIRE(static_cast<bool>(face1));
 
   face2 = make_shared<UnixStreamFace>(client);
-  face2->onReceiveInterest +=
-    bind(&EndToEndFixture::face2_onReceiveInterest, this, _1);
-  face2->onReceiveData +=
-    bind(&EndToEndFixture::face2_onReceiveData, this, _1);
+  face2->onReceiveInterest.connect(bind(&EndToEndFixture::face2_onReceiveInterest, this, _1));
+  face2->onReceiveData.connect(bind(&EndToEndFixture::face2_onReceiveData, this, _1));
 
   shared_ptr<Interest> interest1 = makeInterest("ndn:/TpnzGvW9R");
   shared_ptr<Data>     data1     = makeData("ndn:/KfczhUqVix");
@@ -425,12 +419,9 @@
   void
   onFaceCreated(const shared_ptr<Face>& face)
   {
-    face->onReceiveInterest +=
-      bind(&SimpleEndToEndFixture::onReceiveInterest, this, _1);
-    face->onReceiveData +=
-      bind(&SimpleEndToEndFixture::onReceiveData, this, _1);
-    face->onFail +=
-      bind(&SimpleEndToEndFixture::onFail, this, face);
+    face->onReceiveInterest.connect(bind(&SimpleEndToEndFixture::onReceiveInterest, this, _1));
+    face->onReceiveData.connect(bind(&SimpleEndToEndFixture::onReceiveData, this, _1));
+    face->onFail.connect(bind(&SimpleEndToEndFixture::onFail, this, face));
 
     if (static_cast<bool>(dynamic_pointer_cast<LocalFace>(face))) {
       static_pointer_cast<LocalFace>(face)->setLocalControlHeaderFeature(
diff --git a/tests/daemon/face/websocket.cpp b/tests/daemon/face/websocket.cpp
index fa93b6a..a8c10b5 100644
--- a/tests/daemon/face/websocket.cpp
+++ b/tests/daemon/face/websocket.cpp
@@ -70,12 +70,9 @@
   {
     BOOST_CHECK(!static_cast<bool>(face1));
     face1 = newFace;
-    face1->onReceiveInterest +=
-      bind(&EndToEndFixture::face1_onReceiveInterest, this, _1);
-    face1->onReceiveData +=
-      bind(&EndToEndFixture::face1_onReceiveData, this, _1);
-    face1->onFail +=
-      bind(&EndToEndFixture::face1_onFail, this);
+    face1->onReceiveInterest.connect(bind(&EndToEndFixture::face1_onReceiveInterest, this, _1));
+    face1->onReceiveData.connect(bind(&EndToEndFixture::face1_onReceiveData, this, _1));
+    face1->onFail.connect(bind(&EndToEndFixture::face1_onFail, this));
 
     limitedIo.afterOp();
   }
diff --git a/tests/daemon/fw/forwarder.cpp b/tests/daemon/fw/forwarder.cpp
index 1b74f37..f2af3fb 100644
--- a/tests/daemon/fw/forwarder.cpp
+++ b/tests/daemon/fw/forwarder.cpp
@@ -50,8 +50,8 @@
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
-  face1->afterSend += afterOp;
-  face2->afterSend += afterOp;
+  face1->afterSend.connect(afterOp);
+  face2->afterSend.connect(afterOp);
   forwarder.addFace(face1);
   forwarder.addFace(face2);
 
@@ -433,9 +433,9 @@
   forwarder.addFace(face2);
 
   // cause an Interest sent out of face2 to loop back into face1 after a delay
-  face2->onSendInterest += [&face1] (const Interest& interest) {
+  face2->onSendInterest.connect([&face1] (const Interest& interest) {
     scheduler::schedule(time::milliseconds(170), [&] { face1->receiveInterest(interest); });
-  };
+  });
 
   Fib& fib = forwarder.getFib();
   shared_ptr<fib::Entry> fibEntry = fib.insert(Name("ndn:/A")).first;
diff --git a/tests/daemon/mgmt/channel-status-publisher.cpp b/tests/daemon/mgmt/channel-status-publisher.cpp
index 370efe1..6ab42a3 100644
--- a/tests/daemon/mgmt/channel-status-publisher.cpp
+++ b/tests/daemon/mgmt/channel-status-publisher.cpp
@@ -144,8 +144,7 @@
       m_expectedEntries[expectedEntry.getLocalUri()] = expectedEntry;
     }
 
-  m_face->onReceiveData +=
-    bind(&ChannelStatusPublisherFixture::validatePublish, this, _1);
+  m_face->onReceiveData.connect(bind(&ChannelStatusPublisherFixture::validatePublish, this, _1));
 
   m_publisher.publish();
   BOOST_REQUIRE(m_finished);
@@ -171,8 +170,7 @@
       m_expectedEntries[expectedEntry.getLocalUri()] = expectedEntry;
     }
 
-  m_face->onReceiveData +=
-    bind(&ChannelStatusPublisherFixture::validatePublish, this, _1);
+  m_face->onReceiveData.connect(bind(&ChannelStatusPublisherFixture::validatePublish, this, _1));
 
   m_publisher.publish();
   BOOST_REQUIRE(m_finished);
diff --git a/tests/daemon/mgmt/face-manager.cpp b/tests/daemon/mgmt/face-manager.cpp
index 047f00c..447176c 100644
--- a/tests/daemon/mgmt/face-manager.cpp
+++ b/tests/daemon/mgmt/face-manager.cpp
@@ -797,9 +797,9 @@
 {
   shared_ptr<Interest> command(make_shared<Interest>("/localhost/nfd/faces"));
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 400, "Malformed command");
-  };
+  });
 
   getFace()->sendInterest(*command);
   g_io.run_one();
@@ -811,9 +811,9 @@
 {
   shared_ptr<Interest> command(make_shared<Interest>("/localhost/nfd/faces"));
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 400, "Malformed command");
-  };
+  });
 
   getManager().onFaceRequest(*command);
 
@@ -833,9 +833,9 @@
 
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 401, "Signature required");
-  };
+  });
 
   getManager().onFaceRequest(*command);
 
@@ -856,9 +856,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 403, "Unauthorized command");
-  };
+  });
 
   getManager().onFaceRequest(*command);
 
@@ -894,9 +894,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 501, "Unsupported command");
-  };
+  });
 
   getManager().onFaceRequest(*command);
 
@@ -910,7 +910,7 @@
 public:
 
   ValidatedFaceRequestFixture()
-    : FaceManager(TestFaceTableFixture::m_faceTable, TestFaceManagerCommon::m_face, m_testKeyChain),
+    : FaceManager(TestFaceTableFixture::m_faceTable, getFace(), m_testKeyChain),
       m_createFaceFired(false),
       m_destroyFaceFired(false)
   {
@@ -964,9 +964,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 400, "Malformed command");
-  };
+  });
 
   onValidatedFaceRequest(command);
 
@@ -1035,7 +1035,7 @@
 {
 public:
   LocalControlFixture()
-    : FaceManager(FaceTableFixture::m_faceTable, TestFaceManagerCommon::m_face, m_testKeyChain)
+    : FaceManager(FaceTableFixture::m_faceTable, getFace(), m_testKeyChain)
   {
   }
 };
@@ -1060,11 +1060,11 @@
 
   generateCommand(*enableCommand);
 
-  TestFaceManagerCommon::m_face->onReceiveData +=
-  [this, enableCommand, encodedParameters] (const Data& response) {
-    this->validateControlResponse(response, enableCommand->getName(),
-                                  200, "Success", encodedParameters);
-  };
+  signal::Connection conn = getFace()->onReceiveData.connect(
+      [this, enableCommand, encodedParameters] (const Data& response) {
+        this->validateControlResponse(response, enableCommand->getName(),
+                                      200, "Success", encodedParameters);
+      });
 
   onValidatedFaceRequest(enableCommand);
 
@@ -1072,7 +1072,7 @@
   BOOST_REQUIRE(dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID));
   BOOST_CHECK(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID));
 
-  TestFaceManagerCommon::m_face->onReceiveData.clear();
+  conn.disconnect();
   resetCallbackFired();
 
   Name disable("/localhost/nfd/faces/disable-local-control");
@@ -1083,11 +1083,11 @@
 
   generateCommand(*disableCommand);
 
-  TestFaceManagerCommon::m_face->onReceiveData +=
-  [this, disableCommand, encodedParameters] (const Data& response) {
-    this->validateControlResponse(response, disableCommand->getName(),
-                                  200, "Success", encodedParameters);
-  };
+  getFace()->onReceiveData.connect(
+      [this, disableCommand, encodedParameters] (const Data& response) {
+        this->validateControlResponse(response, disableCommand->getName(),
+                                      200, "Success", encodedParameters);
+      });
 
   onValidatedFaceRequest(disableCommand);
 
@@ -1116,9 +1116,10 @@
 
   generateCommand(*enableCommand);
 
-  TestFaceManagerCommon::m_face->onReceiveData += [this, enableCommand] (const Data& response) {
-    this->validateControlResponse(response, enableCommand->getName(), 410, "Face not found");
-  };
+  signal::Connection conn = getFace()->onReceiveData.connect(
+      [this, enableCommand] (const Data& response) {
+        this->validateControlResponse(response, enableCommand->getName(), 410, "Face not found");
+      });
 
   onValidatedFaceRequest(enableCommand);
 
@@ -1126,7 +1127,7 @@
   BOOST_REQUIRE(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID));
   BOOST_CHECK(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID));
 
-  TestFaceManagerCommon::m_face->onReceiveData.clear();
+  conn.disconnect();
   resetCallbackFired();
 
   Name disable("/localhost/nfd/faces/disable-local-control");
@@ -1137,9 +1138,10 @@
 
   generateCommand(*disableCommand);
 
-  TestFaceManagerCommon::m_face->onReceiveData += [this, disableCommand] (const Data& response) {
-    this->validateControlResponse(response, disableCommand->getName(), 410, "Face not found");
-  };
+  getFace()->onReceiveData.connect(
+      [this, disableCommand] (const Data& response) {
+        this->validateControlResponse(response, disableCommand->getName(), 410, "Face not found");
+      });
 
   onValidatedFaceRequest(disableCommand);
 
@@ -1167,9 +1169,11 @@
 
   generateCommand(*enableCommand);
 
-  TestFaceManagerCommon::m_face->onReceiveData += [this, enableCommand] (const Data& response) {
-    this->validateControlResponse(response, enableCommand->getName(), 400, "Malformed command");
-  };
+  signal::Connection conn = getFace()->onReceiveData.connect(
+      [this, enableCommand] (const Data& response) {
+        this->validateControlResponse(response, enableCommand->getName(),
+                                      400, "Malformed command");
+      });
 
   onValidatedFaceRequest(enableCommand);
 
@@ -1177,7 +1181,7 @@
   BOOST_REQUIRE(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID));
   BOOST_REQUIRE(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID));
 
-  TestFaceManagerCommon::m_face->onReceiveData.clear();
+  conn.disconnect();
   resetCallbackFired();
 
   Name disable("/localhost/nfd/faces/disable-local-control");
@@ -1188,9 +1192,11 @@
 
   generateCommand(*disableCommand);
 
-  TestFaceManagerCommon::m_face->onReceiveData += [this, disableCommand] (const Data& response) {
-    this->validateControlResponse(response, disableCommand->getName(), 400, "Malformed command");
-  };
+  getFace()->onReceiveData.connect(
+      [this, disableCommand] (const Data& response) {
+        this->validateControlResponse(response, disableCommand->getName(),
+                                      400, "Malformed command");
+      });
 
   onValidatedFaceRequest(disableCommand);
 
@@ -1219,15 +1225,17 @@
 
   generateCommand(*enableCommand);
 
-  TestFaceManagerCommon::m_face->onReceiveData += [this, enableCommand] (const Data& response) {
-    this->validateControlResponse(response, enableCommand->getName(), 412, "Face is non-local");
-  };
+  signal::Connection conn = getFace()->onReceiveData.connect(
+      [this, enableCommand] (const Data& response) {
+        this->validateControlResponse(response, enableCommand->getName(),
+                                      412, "Face is non-local");
+      });
 
   onValidatedFaceRequest(enableCommand);
 
   BOOST_REQUIRE(didCallbackFire());
 
-  TestFaceManagerCommon::m_face->onReceiveData.clear();
+  conn.disconnect();
   resetCallbackFired();
 
   Name disable("/localhost/nfd/faces/disable-local-control");
@@ -1238,9 +1246,11 @@
 
   generateCommand(*disableCommand);
 
-  TestFaceManagerCommon::m_face->onReceiveData += [this, disableCommand] (const Data& response) {
-    this->validateControlResponse(response, disableCommand->getName(), 412, "Face is non-local");
-  };
+  getFace()->onReceiveData.connect(
+      [this, disableCommand] (const Data& response) {
+        this->validateControlResponse(response, disableCommand->getName(),
+                                      412, "Face is non-local");
+      });
 
   onValidatedFaceRequest(disableCommand);
 
@@ -1267,11 +1277,11 @@
 
   generateCommand(*enableCommand);
 
-  TestFaceManagerCommon::m_face->onReceiveData +=
-  [this, enableCommand, encodedParameters] (const Data& response) {
-    this->validateControlResponse(response, enableCommand->getName(),
-                                  200, "Success", encodedParameters);
-  };
+  signal::Connection conn = getFace()->onReceiveData.connect(
+      [this, enableCommand, encodedParameters] (const Data& response) {
+        this->validateControlResponse(response, enableCommand->getName(),
+                                      200, "Success", encodedParameters);
+      });
 
   onValidatedFaceRequest(enableCommand);
 
@@ -1280,7 +1290,7 @@
   BOOST_CHECK(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID));
 
 
-  TestFaceManagerCommon::m_face->onReceiveData.clear();
+  conn.disconnect();
   resetCallbackFired();
 
   Name disable("/localhost/nfd/faces/disable-local-control");
@@ -1291,11 +1301,11 @@
 
   generateCommand(*disableCommand);
 
-  TestFaceManagerCommon::m_face->onReceiveData +=
-  [this, disableCommand, encodedParameters] (const Data& response) {
-    this->validateControlResponse(response, disableCommand->getName(),
-                                  200, "Success", encodedParameters);
-  };
+  getFace()->onReceiveData.connect(
+      [this, disableCommand, encodedParameters] (const Data& response) {
+        this->validateControlResponse(response, disableCommand->getName(),
+                                      200, "Success", encodedParameters);
+      });
 
   onValidatedFaceRequest(disableCommand);
 
@@ -1324,9 +1334,10 @@
 
   generateCommand(*enableCommand);
 
-  TestFaceManagerCommon::m_face->onReceiveData += [this, enableCommand] (const Data& response) {
-    this->validateControlResponse(response, enableCommand->getName(), 410, "Face not found");
-  };
+  signal::Connection conn = getFace()->onReceiveData.connect(
+      [this, enableCommand] (const Data& response) {
+        this->validateControlResponse(response, enableCommand->getName(), 410, "Face not found");
+      });
 
   onValidatedFaceRequest(enableCommand);
 
@@ -1335,7 +1346,7 @@
   BOOST_CHECK(!dummy->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID));
 
 
-  TestFaceManagerCommon::m_face->onReceiveData.clear();
+  conn.disconnect();
   resetCallbackFired();
 
   Name disable("/localhost/nfd/faces/disable-local-control");
@@ -1346,9 +1357,11 @@
 
   generateCommand(*disableCommand);
 
-  TestFaceManagerCommon::m_face->onReceiveData += [this, disableCommand] (const Data& response) {
-    this->validateControlResponse(response, disableCommand->getName(), 410, "Face not found");
-  };
+  getFace()->onReceiveData.connect(
+      [this, disableCommand] (const Data& response) {
+        this->validateControlResponse(response, disableCommand->getName(),
+                                      410, "Face not found");
+      });
 
   onValidatedFaceRequest(disableCommand);
 
@@ -1377,15 +1390,17 @@
 
   generateCommand(*enableCommand);
 
-  TestFaceManagerCommon::m_face->onReceiveData += [this, enableCommand] (const Data& response) {
-    this->validateControlResponse(response, enableCommand->getName(), 412, "Face is non-local");
-  };
+  signal::Connection conn = getFace()->onReceiveData.connect(
+      [this, enableCommand] (const Data& response) {
+        this->validateControlResponse(response, enableCommand->getName(),
+                                      412, "Face is non-local");
+      });
 
   onValidatedFaceRequest(enableCommand);
 
   BOOST_REQUIRE(didCallbackFire());
 
-  TestFaceManagerCommon::m_face->onReceiveData.clear();
+  conn.disconnect();
   resetCallbackFired();
 
   Name disable("/localhost/nfd/faces/disable-local-control");
@@ -1396,9 +1411,11 @@
 
   generateCommand(*disableCommand);
 
-  TestFaceManagerCommon::m_face->onReceiveData += [this, disableCommand] (const Data& response) {
-    this->validateControlResponse(response, disableCommand->getName(), 412, "Face is non-local");
-  };
+  getFace()->onReceiveData.connect(
+      [this, disableCommand] (const Data& response) {
+        this->validateControlResponse(response, disableCommand->getName(),
+                                      412, "Face is non-local");
+      });
 
   onValidatedFaceRequest(disableCommand);
 
@@ -1412,7 +1429,7 @@
 public:
   FaceFixture()
     : FaceManager(FaceTableFixture::m_faceTable,
-                  TestFaceManagerCommon::m_face,
+                  getFace(),
                   m_testKeyChain)
     , m_receivedNotification(false)
   {
@@ -1514,9 +1531,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 400, "Malformed command");
-  };
+  });
 
   createFace(*command, parameters);
 
@@ -1536,9 +1553,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 400, "Non-canonical URI");
-  };
+  });
 
   createFace(*command, parameters);
 
@@ -1558,9 +1575,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 400, "Malformed command");
-  };
+  });
 
   createFace(*command, parameters);
 
@@ -1583,9 +1600,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 501, "Unsupported protocol");
-  };
+  });
 
   createFace(*command, parameters);
 
@@ -1622,11 +1639,11 @@
 
   Block encodedResultParameters(resultParameters.wireEncode());
 
-  getFace()->onReceiveData +=
-  [this, command, encodedResultParameters, expectedFaceEvent] (const Data& response) {
-    this->callbackDispatch(response,command->getName(), 200, "Success",
-                           encodedResultParameters, expectedFaceEvent);
-  };
+  getFace()->onReceiveData.connect(
+      [this, command, encodedResultParameters, expectedFaceEvent] (const Data& response) {
+        this->callbackDispatch(response,command->getName(), 200, "Success",
+                               encodedResultParameters, expectedFaceEvent);
+      });
 
   onCreated(command->getName(), parameters, dummy);
 
@@ -1648,9 +1665,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 408, "unit-test-reason");
-  };
+  });
 
   onConnectFailed(command->getName(), "unit-test-reason");
 
@@ -1684,11 +1701,11 @@
                    .setFaceScope(ndn::nfd::FACE_SCOPE_NON_LOCAL)
                    .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
 
-  getFace()->onReceiveData +=
-  [this, command, encodedParameters, expectedFaceEvent] (const Data& response) {
-    this->callbackDispatch(response,command->getName(), 200, "Success",
-                           encodedParameters, expectedFaceEvent);
-  };
+  getFace()->onReceiveData.connect(
+      [this, command, encodedParameters, expectedFaceEvent] (const Data& response) {
+        this->callbackDispatch(response,command->getName(), 200, "Success",
+                               encodedParameters, expectedFaceEvent);
+      });
 
   destroyFace(*command, parameters);
 
@@ -1737,8 +1754,8 @@
 
   ndn::EncodingBuffer buffer;
 
-  m_face->onReceiveData +=
-    bind(&FaceStatusPublisherFixture::decodeFaceStatusBlock, this, _1);
+  m_face->onReceiveData.connect(bind(&FaceStatusPublisherFixture::decodeFaceStatusBlock,
+                                     this, _1));
 
   m_manager.listFaces(*command);
   BOOST_REQUIRE(m_finished);
@@ -1777,8 +1794,8 @@
   ndn::nfd::ChannelStatus expectedEntry;
   expectedEntry.setLocalUri(DummyChannel("dummy://").getUri().toString());
 
-  m_face->onReceiveData +=
-    bind(&ChannelStatusFixture::validatePublish, this, _1, expectedEntry);
+  m_face->onReceiveData.connect(bind(&ChannelStatusFixture::validatePublish,
+                                     this, _1, expectedEntry));
 
   m_manager.listChannels(*request);
   BOOST_REQUIRE(m_callbackFired);
@@ -1828,8 +1845,8 @@
   shared_ptr<DummyLocalFace> face2(make_shared<DummyLocalFace>("tcp://", "tcp://"));
   add(face2);
 
-  m_face->onReceiveData +=
-    bind(&FaceQueryStatusPublisherFixture::decodeFaceStatusBlock, this, _1);
+  m_face->onReceiveData.connect(bind(&FaceQueryStatusPublisherFixture::decodeFaceStatusBlock,
+                                     this, _1));
 
   m_manager.listQueriedFaces(*query);
   BOOST_REQUIRE(m_finished);
@@ -1846,8 +1863,7 @@
   shared_ptr<DummyLocalFace> face(make_shared<DummyLocalFace>());
   add(face);
 
-  m_face->onReceiveData +=
-    bind(&FaceQueryStatusPublisherFixture::decodeNackBlock, this, _1);
+  m_face->onReceiveData.connect(bind(&FaceQueryStatusPublisherFixture::decodeNackBlock, this, _1));
 
   m_manager.listQueriedFaces(*query);
   BOOST_REQUIRE(m_finished);
diff --git a/tests/daemon/mgmt/face-status-publisher.cpp b/tests/daemon/mgmt/face-status-publisher.cpp
index 145fe0e..87ebba2 100644
--- a/tests/daemon/mgmt/face-status-publisher.cpp
+++ b/tests/daemon/mgmt/face-status-publisher.cpp
@@ -53,8 +53,8 @@
 
   ndn::EncodingBuffer buffer;
 
-  m_face->onReceiveData +=
-    bind(&FaceStatusPublisherFixture::decodeFaceStatusBlock, this, _1);
+  m_face->onReceiveData.connect(
+      bind(&FaceStatusPublisherFixture::decodeFaceStatusBlock, this, _1));
 
   m_publisher.publish();
   BOOST_REQUIRE(m_finished);
diff --git a/tests/daemon/mgmt/fib-enumeration-publisher.cpp b/tests/daemon/mgmt/fib-enumeration-publisher.cpp
index ed330aa..dc212d2 100644
--- a/tests/daemon/mgmt/fib-enumeration-publisher.cpp
+++ b/tests/daemon/mgmt/fib-enumeration-publisher.cpp
@@ -77,8 +77,8 @@
 
   ndn::EncodingBuffer buffer;
 
-  m_face->onReceiveData +=
-    bind(&FibEnumerationPublisherFixture::decodeFibEntryBlock, this, _1);
+  m_face->onReceiveData.connect(
+      bind(&FibEnumerationPublisherFixture::decodeFibEntryBlock, this, _1));
 
   m_publisher.publish();
   BOOST_REQUIRE(m_finished);
diff --git a/tests/daemon/mgmt/fib-manager.cpp b/tests/daemon/mgmt/fib-manager.cpp
index 525dfc8..c5a437a 100644
--- a/tests/daemon/mgmt/fib-manager.cpp
+++ b/tests/daemon/mgmt/fib-manager.cpp
@@ -241,9 +241,9 @@
 
   shared_ptr<Interest> command = makeInterest("/localhost/nfd/fib");
 
-  face->onReceiveData += [this, command] (const Data& response) {
+  face->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 400, "Malformed command");
-  };
+  });
 
   face->sendInterest(*command);
   g_io.run_one();
@@ -259,9 +259,9 @@
 
   Interest command("/localhost/nfd/fib");
 
-  face->onReceiveData += [this, command] (const Data& response) {
+  face->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command.getName(), 400, "Malformed command");
-  };
+  });
 
   getFibManager().onFibRequest(command);
 
@@ -286,9 +286,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  face->onReceiveData += [this, command] (const Data& response) {
+  face->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 501, "Unsupported command");
-  };
+  });
 
   getFibManager().onFibRequest(*command);
 
@@ -314,9 +314,9 @@
 
   Interest command(commandName);
 
-  face->onReceiveData += [this, command] (const Data& response) {
+  face->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command.getName(), 401, "Signature required");
-  };
+  });
 
   getFibManager().onFibRequest(command);
 
@@ -344,9 +344,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  face->onReceiveData += [this, command] (const Data& response) {
+  face->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 403, "Unauthorized command");
-  };
+  });
 
   getFibManager().onFibRequest(*command);
 
@@ -367,9 +367,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  face->onReceiveData += [this, command] (const Data& response) {
+  face->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 400, "Malformed command");
-  };
+  });
 
   getFibManager().onFibRequest(*command);
 
@@ -396,9 +396,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  face->onReceiveData += [this, command] (const Data& response) {
+  face->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 410, "Face not found");
-  };
+  });
 
   getFibManager().onFibRequest(*command);
 
@@ -436,17 +436,18 @@
     command->setIncomingFaceId(1);
     generateCommand(*command);
 
-    face->onReceiveData += [this, command, encodedExpectedParameters] (const Data& response) {
-      this->validateControlResponse(response, command->getName(),
-                                    200, "Success", encodedExpectedParameters);
-    };
+    signal::Connection conn = face->onReceiveData.connect(
+        [this, command, encodedExpectedParameters] (const Data& response) {
+          this->validateControlResponse(response, command->getName(),
+                                        200, "Success", encodedExpectedParameters);
+        });
 
     getFibManager().onFibRequest(*command);
 
     BOOST_REQUIRE(didCallbackFire());
     BOOST_REQUIRE(addedNextHopWithFace(getFib(), "/hello", 0, 101, getFace(1)));
 
-    face->onReceiveData.clear();
+    conn.disconnect();
     getFib().erase("/hello");
     BOOST_REQUIRE_EQUAL(getFib().size(), 0);
   }
@@ -472,10 +473,10 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  face->onReceiveData += [this, command, encodedParameters] (const Data& response) {
+  face->onReceiveData.connect([this, command, encodedParameters] (const Data& response) {
     this->validateControlResponse(response, command->getName(),
                                   200, "Success", encodedParameters);
-  };
+  });
 
   getFibManager().onFibRequest(*command);
 
@@ -507,10 +508,10 @@
   resultParameters.setFaceId(1);
   resultParameters.setCost(0);
 
-  face->onReceiveData += [this, command, resultParameters] (const Data& response) {
+  face->onReceiveData.connect([this, command, resultParameters] (const Data& response) {
     this->validateControlResponse(response, command->getName(),
                                   200, "Success", resultParameters.wireEncode());
-  };
+  });
 
   getFibManager().onFibRequest(*command);
 
@@ -540,10 +541,11 @@
       shared_ptr<Interest> command(make_shared<Interest>(commandName));
       generateCommand(*command);
 
-      face->onReceiveData += [this, command, encodedParameters] (const Data& response) {
-        this->validateControlResponse(response, command->getName(),
-                                      200, "Success", encodedParameters);
-      };
+      signal::Connection conn = face->onReceiveData.connect(
+          [this, command, encodedParameters] (const Data& response) {
+            this->validateControlResponse(response, command->getName(),
+                                          200, "Success", encodedParameters);
+          });
 
       getFibManager().onFibRequest(*command);
       BOOST_REQUIRE(didCallbackFire());
@@ -564,7 +566,7 @@
           BOOST_FAIL("Failed to find expected fib entry");
         }
 
-      face->onReceiveData.clear();
+      conn.disconnect();
     }
 }
 
@@ -589,18 +591,19 @@
     shared_ptr<Interest> command(make_shared<Interest>(commandName));
     generateCommand(*command);
 
-    face->onReceiveData += [this, command, encodedParameters] (const Data& response) {
-      this->validateControlResponse(response, command->getName(),
-                                    200, "Success", encodedParameters);
-    };
+    signal::Connection conn = face->onReceiveData.connect(
+        [this, command, encodedParameters] (const Data& response) {
+          this->validateControlResponse(response, command->getName(),
+                                        200, "Success", encodedParameters);
+        });
 
     getFibManager().onFibRequest(*command);
 
     BOOST_REQUIRE(didCallbackFire());
-  }
 
-  resetCallbackFired();
-  face->onReceiveData.clear();
+    resetCallbackFired();
+    conn.disconnect();
+  }
 
   {
     parameters.setCost(102);
@@ -614,10 +617,10 @@
     shared_ptr<Interest> command(make_shared<Interest>(commandName));
     generateCommand(*command);
 
-    face->onReceiveData += [this, command, encodedParameters] (const Data& response) {
+    face->onReceiveData.connect([this, command, encodedParameters] (const Data& response) {
       this->validateControlResponse(response, command->getName(),
                                     200, "Success", encodedParameters);
-    };
+    });
 
     getFibManager().onFibRequest(*command);
 
@@ -661,9 +664,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  face->onReceiveData += [this, command] (const Data& response) {
+  face->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 400, "Malformed command");
-  };
+  });
 
   getFibManager().onFibRequest(*command);
 
@@ -705,17 +708,18 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   fixture->generateCommand(*command);
 
-  face->onReceiveData += [fixture, command, encodedParameters] (const Data& response) {
-    fixture->validateControlResponse(response, command->getName(),
-                                     200, "Success", encodedParameters);
-  };
+  signal::Connection conn = face->onReceiveData.connect(
+      [fixture, command, encodedParameters] (const Data& response) {
+        fixture->validateControlResponse(response, command->getName(),
+                                         200, "Success", encodedParameters);
+      });
 
   manager.onFibRequest(*command);
 
   BOOST_REQUIRE(fixture->didCallbackFire());
 
   fixture->resetCallbackFired();
-  face->onReceiveData.clear();
+  conn.disconnect();
 }
 
 BOOST_AUTO_TEST_CASE(RemoveNextHop)
@@ -767,10 +771,10 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  face->onReceiveData += [this, command, encodedParameters] (const Data& response) {
+  face->onReceiveData.connect([this, command, encodedParameters] (const Data& response) {
     this->validateControlResponse(response, command->getName(),
                                   200, "Success", encodedParameters);
-  };
+  });
 
   getFibManager().onFibRequest(*command);
 
@@ -796,10 +800,10 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  face->onReceiveData += [this, command, encodedParameters] (const Data& response) {
+  face->onReceiveData.connect([this, command, encodedParameters] (const Data& response) {
     this->validateControlResponse(response, command->getName(),
                                   200, "Success", encodedParameters);
-  };
+  });
 
   getFibManager().onFibRequest(*command);
 
@@ -824,9 +828,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  face->onReceiveData += [this, command] (const Data& response) {
+  face->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 400, "Malformed command");
-  };
+  });
 
   getFibManager().onFibRequest(*command);
 
@@ -859,16 +863,17 @@
     resultParameters.setFaceId(1);
     resultParameters.setName("/hello");
 
-    face->onReceiveData += [this, command, resultParameters] (const Data& response) {
-      this->validateControlResponse(response, command->getName(),
-                                    200, "Success", resultParameters.wireEncode());
-    };
+    signal::Connection conn = face->onReceiveData.connect(
+        [this, command, resultParameters] (const Data& response) {
+          this->validateControlResponse(response, command->getName(),
+                                        200, "Success", resultParameters.wireEncode());
+        });
 
     getFibManager().onFibRequest(*command);
 
     BOOST_REQUIRE(didCallbackFire());
 
-    face->onReceiveData.clear();
+    conn.disconnect();
   }
 }
 
@@ -905,8 +910,8 @@
 
   ndn::EncodingBuffer buffer;
 
-  m_face->onReceiveData +=
-    bind(&FibEnumerationPublisherFixture::decodeFibEntryBlock, this, _1);
+  m_face->onReceiveData.connect(bind(&FibEnumerationPublisherFixture::decodeFibEntryBlock,
+                                     this, _1));
 
   shared_ptr<Interest> command(make_shared<Interest>("/localhost/nfd/fib/list"));
 
diff --git a/tests/daemon/mgmt/internal-face.cpp b/tests/daemon/mgmt/internal-face.cpp
index 2215c0e..ca2a899 100644
--- a/tests/daemon/mgmt/internal-face.cpp
+++ b/tests/daemon/mgmt/internal-face.cpp
@@ -31,8 +31,6 @@
 namespace nfd {
 namespace tests {
 
-NFD_LOG_INIT("InternalFaceTest");
-
 class InternalFaceFixture : protected BaseFixture
 {
 public:
@@ -112,7 +110,7 @@
 
   bool didPutData = false;
   Name dataName("/hello");
-  face->onReceiveData += bind(&validatePutData, ref(didPutData), dataName, _1);
+  face->onReceiveData.connect(bind(&validatePutData, ref(didPutData), dataName, _1));
 
   Data testData(dataName);
   m_keyChain.sign(testData);
diff --git a/tests/daemon/mgmt/manager-base.cpp b/tests/daemon/mgmt/manager-base.cpp
index 0aa7077..cfecc7d 100644
--- a/tests/daemon/mgmt/manager-base.cpp
+++ b/tests/daemon/mgmt/manager-base.cpp
@@ -166,9 +166,9 @@
   ndn::nfd::ControlParameters parameters;
   parameters.setName("/test/body");
 
-  getInternalFace()->onReceiveData += [this, parameters] (const Data& response) {
+  getInternalFace()->onReceiveData.connect([this, parameters] (const Data& response) {
     this->validateControlResponse(response, "/response", 100, "test", parameters.wireEncode());
-  };
+  });
 
   testSendResponse("/response", 100, "test", parameters.wireEncode());
   BOOST_REQUIRE(didCallbackFire());
@@ -177,9 +177,9 @@
 
 BOOST_AUTO_TEST_CASE(SendResponse3Arg)
 {
-  getInternalFace()->onReceiveData += [this] (const Data& response) {
+  getInternalFace()->onReceiveData.connect([this] (const Data& response) {
     this->validateControlResponse(response, "/response", 100, "test");
-  };
+  });
 
   testSendResponse("/response", 100, "test");
   BOOST_REQUIRE(didCallbackFire());
@@ -187,9 +187,9 @@
 
 BOOST_AUTO_TEST_CASE(SendResponse2Arg)
 {
-  getInternalFace()->onReceiveData += [this] (const Data& response) {
+  getInternalFace()->onReceiveData.connect([this] (const Data& response) {
     this->validateControlResponse(response, "/response", 100, "test");
-  };
+  });
 
   ControlResponse response(100, "test");
 
diff --git a/tests/daemon/mgmt/status-server.cpp b/tests/daemon/mgmt/status-server.cpp
index bda69a4..553e3fd 100644
--- a/tests/daemon/mgmt/status-server.cpp
+++ b/tests/daemon/mgmt/status-server.cpp
@@ -50,7 +50,7 @@
   time::system_clock::TimePoint t1 = time::system_clock::now();
   Forwarder forwarder;
   shared_ptr<InternalFace> internalFace = make_shared<InternalFace>();
-  internalFace->onReceiveData += &interceptResponse;
+  internalFace->onReceiveData.connect(&interceptResponse);
   ndn::KeyChain keyChain;
   StatusServer statusServer(internalFace, ref(forwarder), keyChain);
   time::system_clock::TimePoint t2 = time::system_clock::now();
diff --git a/tests/daemon/mgmt/strategy-choice-manager.cpp b/tests/daemon/mgmt/strategy-choice-manager.cpp
index 570c1d8..2125001 100644
--- a/tests/daemon/mgmt/strategy-choice-manager.cpp
+++ b/tests/daemon/mgmt/strategy-choice-manager.cpp
@@ -225,9 +225,9 @@
 {
   shared_ptr<Interest> command(make_shared<Interest>("/localhost/nfd/strategy-choice"));
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 400, "Malformed command");
-  };
+  });
 
   getFace()->sendInterest(*command);
   g_io.run_one();
@@ -239,9 +239,9 @@
 {
   shared_ptr<Interest> command(make_shared<Interest>("/localhost/nfd/strategy-choice"));
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 400, "Malformed command");
-  };
+  });
 
   getManager().onStrategyChoiceRequest(*command);
 
@@ -262,9 +262,9 @@
 
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 401, "Signature required");
-  };
+  });
 
   getManager().onStrategyChoiceRequest(*command);
 
@@ -287,9 +287,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 403, "Unauthorized command");
-  };
+  });
 
   getManager().onStrategyChoiceRequest(*command);
 
@@ -311,9 +311,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 501, "Unsupported command");
-  };
+  });
 
   getManager().onValidatedStrategyChoiceRequest(command);
 
@@ -329,9 +329,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 400, "Malformed command");
-  };
+  });
 
   getManager().onValidatedStrategyChoiceRequest(command);
 
@@ -352,10 +352,10 @@
 
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
 
-  getFace()->onReceiveData += [this, command, encodedParameters] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command, encodedParameters] (const Data& response) {
     this->validateControlResponse(response, command->getName(),
                                   200, "Success", encodedParameters);
-  };
+  });
 
   getManager().onValidatedStrategyChoiceRequest(command);
 
@@ -378,10 +378,10 @@
 
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
 
-  getFace()->onReceiveData += [this, command, encodedParameters] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command, encodedParameters] (const Data& response) {
     this->validateControlResponse(response, command->getName(),
                                   200, "Success", encodedParameters);
-  };
+  });
 
   getManager().onValidatedStrategyChoiceRequest(command);
 
@@ -408,10 +408,10 @@
   responseParameters.setName("/test");
   responseParameters.setStrategy("/localhost/nfd/strategy/test-strategy-c/%FD%02");
 
-  getFace()->onReceiveData += [this, command, responseParameters] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command, responseParameters] (const Data& response) {
     this->validateControlResponse(response, command->getName(),
                                   200, "Success", responseParameters.wireEncode());
-  };
+  });
 
   getManager().onValidatedStrategyChoiceRequest(command);
 
@@ -433,9 +433,9 @@
 
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 400, "Malformed command");
-  };
+  });
 
   getManager().onValidatedStrategyChoiceRequest(command);
 
@@ -455,9 +455,9 @@
 
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 400, "Malformed command");
-  };
+  });
 
   getManager().onValidatedStrategyChoiceRequest(command);
 
@@ -481,9 +481,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 504, "Unsupported strategy");
-  };
+  });
 
   getManager().onValidatedStrategyChoiceRequest(command);
 
@@ -555,10 +555,10 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  getFace()->onReceiveData += [this, command, encodedParameters] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command, encodedParameters] (const Data& response) {
     this->validateControlResponse(response, command->getName(),
                                   200, "Success", encodedParameters);
-  };
+  });
 
   getManager().onValidatedStrategyChoiceRequest(command);
 
@@ -582,10 +582,10 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(),
                                   403, "Cannot unset root prefix strategy");
-  };
+  });
 
   getManager().onValidatedStrategyChoiceRequest(command);
 
@@ -612,9 +612,9 @@
   shared_ptr<Interest> command(make_shared<Interest>(commandName));
   generateCommand(*command);
 
-  getFace()->onReceiveData += [this, command] (const Data& response) {
+  getFace()->onReceiveData.connect([this, command] (const Data& response) {
     this->validateControlResponse(response, command->getName(), 400, "Malformed command");
-  };
+  });
 
   getManager().onValidatedStrategyChoiceRequest(command);
 
@@ -633,8 +633,8 @@
   expectedChoice.setStrategy("/localhost/nfd/strategy/test-strategy-a");
   expectedChoice.setName("/");
 
-  getFace()->onReceiveData +=
-    bind(&StrategyChoiceManagerFixture::validateList, this, _1, expectedChoice);
+  getFace()->onReceiveData.connect(bind(&StrategyChoiceManagerFixture::validateList,
+                                        this, _1, expectedChoice));
 
   m_manager.onStrategyChoiceRequest(*command);
   BOOST_REQUIRE(didCallbackFire());
diff --git a/tests/daemon/mgmt/strategy-choice-publisher.cpp b/tests/daemon/mgmt/strategy-choice-publisher.cpp
index e85bc4a..e747c38 100644
--- a/tests/daemon/mgmt/strategy-choice-publisher.cpp
+++ b/tests/daemon/mgmt/strategy-choice-publisher.cpp
@@ -153,8 +153,7 @@
   m_expectedEntries["/test/a"] = expectedEntryA;
   m_expectedEntries["/test/b"] = expectedEntryB;
 
-  m_face->onReceiveData +=
-    bind(&StrategyChoicePublisherFixture::validatePublish, this, _1);
+  m_face->onReceiveData.connect(bind(&StrategyChoicePublisherFixture::validatePublish, this, _1));
 
   m_publisher.publish();
   BOOST_REQUIRE(m_finished);