face: use move semantics for sockets where possible

Change-Id: I2af595073f862c570c1ce0dcb3717f3d2b9cfd71
Refs: #2613
diff --git a/daemon/face/datagram-face.hpp b/daemon/face/datagram-face.hpp
index adbf9e6..82d0347 100644
--- a/daemon/face/datagram-face.hpp
+++ b/daemon/face/datagram-face.hpp
@@ -45,7 +45,7 @@
    * \param socket      Protocol-specific socket for the created face
    */
   DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
-               const shared_ptr<typename protocol::socket>& socket);
+               typename protocol::socket socket);
 
   // from Face
   void
@@ -91,7 +91,7 @@
   resetRecentUsage();
 
 protected:
-  shared_ptr<typename protocol::socket> m_socket;
+  typename protocol::socket m_socket;
 
   NFD_LOG_INCLASS_DECLARE();
 
@@ -104,14 +104,16 @@
 template<class T, class U>
 inline
 DatagramFace<T, U>::DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
-                                 const shared_ptr<typename DatagramFace::protocol::socket>& socket)
+                                 typename DatagramFace::protocol::socket socket)
   : Face(remoteUri, localUri, false, std::is_same<U, Multicast>::value)
-  , m_socket(socket)
+  , m_socket(std::move(socket))
 {
   NFD_LOG_FACE_INFO("Creating face");
 
-  m_socket->async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE), 0,
-                          bind(&DatagramFace<T, U>::handleReceive, this, _1, _2));
+  m_socket.async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
+                         bind(&DatagramFace<T, U>::handleReceive, this,
+                              boost::asio::placeholders::error,
+                              boost::asio::placeholders::bytes_transferred));
 }
 
 template<class T, class U>
@@ -123,8 +125,11 @@
   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));
+  m_socket.async_send(boost::asio::buffer(payload.wire(), payload.size()),
+                      bind(&DatagramFace<T, U>::handleSend, this,
+                           boost::asio::placeholders::error,
+                           boost::asio::placeholders::bytes_transferred,
+                           payload));
 }
 
 template<class T, class U>
@@ -136,15 +141,18 @@
   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));
+  m_socket.async_send(boost::asio::buffer(payload.wire(), payload.size()),
+                      bind(&DatagramFace<T, U>::handleSend, this,
+                           boost::asio::placeholders::error,
+                           boost::asio::placeholders::bytes_transferred,
+                           payload));
 }
 
 template<class T, class U>
 inline void
 DatagramFace<T, U>::close()
 {
-  if (!m_socket->is_open())
+  if (!m_socket.is_open())
     return;
 
   NFD_LOG_FACE_INFO("Closing face");
@@ -161,7 +169,7 @@
     return;
 
   // this should be unnecessary, but just in case
-  if (!m_socket->is_open()) {
+  if (!m_socket.is_open()) {
     this->fail("Tunnel closed");
     return;
   }
@@ -198,9 +206,11 @@
 {
   receiveDatagram(m_inputBuffer, nBytesReceived, error);
 
-  if (m_socket->is_open())
-    m_socket->async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE), 0,
-                            bind(&DatagramFace<T, U>::handleReceive, this, _1, _2));
+  if (m_socket.is_open())
+    m_socket.async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
+                           bind(&DatagramFace<T, U>::handleReceive, this,
+                                boost::asio::placeholders::error,
+                                boost::asio::placeholders::bytes_transferred));
 }
 
 template<class T, class U>
@@ -209,7 +219,7 @@
                                     size_t nBytesReceived,
                                     const boost::system::error_code& error)
 {
-  if (error || nBytesReceived == 0)
+  if (error)
     return processErrorCode(error);
 
   NFD_LOG_FACE_TRACE("Received: " << nBytesReceived << " bytes");
@@ -257,8 +267,8 @@
 
   // use the non-throwing variants and ignore errors, if any
   boost::system::error_code error;
-  m_socket->shutdown(protocol::socket::shutdown_both, error);
-  m_socket->close(error);
+  m_socket.shutdown(protocol::socket::shutdown_both, error);
+  m_socket.close(error);
   // after this, handlers will be called with an error code
 
   // ensure that the Face object is alive at least until all pending
diff --git a/daemon/face/ethernet-face.cpp b/daemon/face/ethernet-face.cpp
index a2b10e3..05d1f71 100644
--- a/daemon/face/ethernet-face.cpp
+++ b/daemon/face/ethernet-face.cpp
@@ -62,12 +62,12 @@
 
 const time::nanoseconds EthernetFace::REASSEMBLER_LIFETIME = time::seconds(60);
 
-EthernetFace::EthernetFace(const shared_ptr<boost::asio::posix::stream_descriptor>& socket,
+EthernetFace::EthernetFace(boost::asio::posix::stream_descriptor socket,
                            const NetworkInterfaceInfo& interface,
                            const ethernet::Address& address)
   : Face(FaceUri(address), FaceUri::fromDev(interface.name), false, true)
   , m_pcap(nullptr, pcap_close)
-  , m_socket(socket)
+  , m_socket(std::move(socket))
 #if defined(__linux__)
   , m_interfaceIndex(interface.index)
 #endif
@@ -88,7 +88,7 @@
   // need to duplicate the fd, otherwise both pcap_close()
   // and stream_descriptor::close() will try to close the
   // same fd and one of them will fail
-  m_socket->assign(::dup(fd));
+  m_socket.assign(::dup(fd));
 
   m_interfaceMtu = getInterfaceMtu();
   NFD_LOG_FACE_DEBUG("Interface MTU is: " << m_interfaceMtu);
@@ -109,14 +109,10 @@
       pcap_set_promisc(m_pcap.get(), 1);
     }
 
-  m_socket->async_read_some(boost::asio::null_buffers(),
-                            bind(&EthernetFace::handleRead, this,
-                                 boost::asio::placeholders::error,
-                                 boost::asio::placeholders::bytes_transferred));
-}
-
-EthernetFace::~EthernetFace()
-{
+  m_socket.async_read_some(boost::asio::null_buffers(),
+                           bind(&EthernetFace::handleRead, this,
+                                boost::asio::placeholders::error,
+                                boost::asio::placeholders::bytes_transferred));
 }
 
 void
@@ -154,9 +150,9 @@
   NFD_LOG_FACE_INFO("Closing face");
 
   boost::system::error_code error;
-  m_socket->cancel(error); // ignore errors
-  m_socket->close(error);  // ignore errors
-  m_pcap.reset(nullptr);
+  m_socket.cancel(error); // ignore errors
+  m_socket.close(error);  // ignore errors
+  m_pcap.reset();
 
   fail("Face closed");
 }
@@ -211,7 +207,7 @@
   mr.mr_alen = m_destAddress.size();
   std::copy(m_destAddress.begin(), m_destAddress.end(), mr.mr_address);
 
-  if (::setsockopt(m_socket->native_handle(), SOL_PACKET,
+  if (::setsockopt(m_socket.native_handle(), SOL_PACKET,
                    PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == 0)
     return true; // success
 
@@ -249,7 +245,7 @@
   static_assert(sizeof(ifr.ifr_addr) >= offsetof(sockaddr_dl, sdl_data) + ethernet::ADDR_LEN,
                 "ifr_addr in struct ifreq is too small on this platform");
 #else
-  int fd = m_socket->native_handle();
+  int fd = m_socket.native_handle();
 
   ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
   std::copy(m_destAddress.begin(), m_destAddress.end(), ifr.ifr_hwaddr.sa_data);
@@ -350,10 +346,10 @@
     }
 #endif
 
-  m_socket->async_read_some(boost::asio::null_buffers(),
-                            bind(&EthernetFace::handleRead, this,
-                                 boost::asio::placeholders::error,
-                                 boost::asio::placeholders::bytes_transferred));
+  m_socket.async_read_some(boost::asio::null_buffers(),
+                           bind(&EthernetFace::handleRead, this,
+                                boost::asio::placeholders::error,
+                                boost::asio::placeholders::bytes_transferred));
 }
 
 void
@@ -415,8 +411,7 @@
   ndnlp::NdnlpData fragment;
   std::tie(isOk, fragment) = ndnlp::NdnlpData::fromBlock(fragmentBlock);
   if (!isOk) {
-    NFD_LOG_FACE_WARN("Received invalid NDNLP fragment from "
-                      << sourceAddress.toString());
+    NFD_LOG_FACE_WARN("Received invalid NDNLP fragment from " << sourceAddress.toString());
     return;
   }
 
@@ -444,7 +439,7 @@
 }
 
 size_t
-EthernetFace::getInterfaceMtu() const
+EthernetFace::getInterfaceMtu()
 {
 #ifdef SIOCGIFMTU
 #if defined(__APPLE__) || defined(__FreeBSD__)
@@ -453,7 +448,7 @@
   udp::socket sock(ref(getGlobalIoService()), udp::v4());
   int fd = sock.native_handle();
 #else
-  int fd = m_socket->native_handle();
+  int fd = m_socket.native_handle();
 #endif
 
   ifreq ifr{};
diff --git a/daemon/face/ethernet-face.hpp b/daemon/face/ethernet-face.hpp
index e9f0e2a..2bbd781 100644
--- a/daemon/face/ethernet-face.hpp
+++ b/daemon/face/ethernet-face.hpp
@@ -60,12 +60,10 @@
     Error(const std::string& what) : Face::Error(what) {}
   };
 
-  EthernetFace(const shared_ptr<boost::asio::posix::stream_descriptor>& socket,
+  EthernetFace(boost::asio::posix::stream_descriptor socket,
                const NetworkInterfaceInfo& interface,
                const ethernet::Address& address);
 
-  ~EthernetFace() DECL_OVERRIDE;
-
   /// send an Interest
   void
   sendInterest(const Interest& interest) DECL_OVERRIDE;
@@ -138,7 +136,7 @@
    * @brief Returns the MTU of the underlying network interface
    */
   size_t
-  getInterfaceMtu() const;
+  getInterfaceMtu();
 
 private:
   struct Reassembler
@@ -148,7 +146,7 @@
   };
 
   unique_ptr<pcap_t, void(*)(pcap_t*)> m_pcap;
-  shared_ptr<boost::asio::posix::stream_descriptor> m_socket;
+  boost::asio::posix::stream_descriptor m_socket;
 
 #if defined(__linux__)
   int m_interfaceIndex;
diff --git a/daemon/face/ethernet-factory.cpp b/daemon/face/ethernet-factory.cpp
index 0126b48..7c2d2f7 100644
--- a/daemon/face/ethernet-factory.cpp
+++ b/daemon/face/ethernet-factory.cpp
@@ -44,8 +44,8 @@
   if (face)
     return face;
 
-  auto socket = make_shared<boost::asio::posix::stream_descriptor>(ref(getGlobalIoService()));
-  face = make_shared<EthernetFace>(socket, interface, address);
+  face = make_shared<EthernetFace>(boost::asio::posix::stream_descriptor(getGlobalIoService()),
+                                   interface, address);
 
   auto key = std::make_pair(interface.name, address);
   face->onFail.connectSingleShot([this, key] (const std::string& reason) {
diff --git a/daemon/face/multicast-udp-face.cpp b/daemon/face/multicast-udp-face.cpp
index 910f1cb..8ac07af 100644
--- a/daemon/face/multicast-udp-face.cpp
+++ b/daemon/face/multicast-udp-face.cpp
@@ -31,13 +31,12 @@
                                                 MulticastUdpFace::protocol, Multicast,
                                                 "MulticastUdpFace");
 
-MulticastUdpFace::MulticastUdpFace(const shared_ptr<MulticastUdpFace::protocol::socket>& recvSocket,
-                                   const shared_ptr<MulticastUdpFace::protocol::socket>& sendSocket,
-                                   const MulticastUdpFace::protocol::endpoint& localEndpoint,
-                                   const MulticastUdpFace::protocol::endpoint& multicastEndpoint)
-  : DatagramFace(FaceUri(multicastEndpoint), FaceUri(localEndpoint), recvSocket)
-  , m_multicastGroup(multicastEndpoint)
-  , m_sendSocket(sendSocket)
+MulticastUdpFace::MulticastUdpFace(const protocol::endpoint& multicastGroup,
+                                   const FaceUri& localUri,
+                                   protocol::socket recvSocket, protocol::socket sendSocket)
+  : DatagramFace(FaceUri(multicastGroup), localUri, std::move(recvSocket))
+  , m_multicastGroup(multicastGroup)
+  , m_sendSocket(std::move(sendSocket))
 {
 }
 
@@ -48,20 +47,10 @@
 }
 
 void
-MulticastUdpFace::sendBlock(const Block& block)
-{
-  m_sendSocket->async_send_to(boost::asio::buffer(block.wire(), block.size()),
-                              m_multicastGroup,
-                              bind(&MulticastUdpFace::handleSend, this, _1, _2, block));
-}
-
-void
 MulticastUdpFace::sendInterest(const Interest& interest)
 {
   NFD_LOG_FACE_TRACE(__func__);
-
   this->emitSignal(onSendInterest, interest);
-
   sendBlock(interest.wireEncode());
 }
 
@@ -69,12 +58,20 @@
 MulticastUdpFace::sendData(const Data& data)
 {
   NFD_LOG_FACE_TRACE(__func__);
-
   /// \todo After this face implements duplicate suppression, onSendData should
   ///       be emitted only when data is actually sent out. See also #2555
   this->emitSignal(onSendData, data);
-
   sendBlock(data.wireEncode());
 }
 
+void
+MulticastUdpFace::sendBlock(const Block& block)
+{
+  m_sendSocket.async_send_to(boost::asio::buffer(block.wire(), block.size()), m_multicastGroup,
+                             bind(&MulticastUdpFace::handleSend, this,
+                                  boost::asio::placeholders::error,
+                                  boost::asio::placeholders::bytes_transferred,
+                                  block));
+}
+
 } // namespace nfd
diff --git a/daemon/face/multicast-udp-face.hpp b/daemon/face/multicast-udp-face.hpp
index eff4394..7aab4a7 100644
--- a/daemon/face/multicast-udp-face.hpp
+++ b/daemon/face/multicast-udp-face.hpp
@@ -40,10 +40,8 @@
   /**
    * \brief Creates a UDP-based face for multicast communication
    */
-  MulticastUdpFace(const shared_ptr<protocol::socket>& recvSocket,
-                   const shared_ptr<protocol::socket>& sendSocket,
-                   const protocol::endpoint& localEndpoint,
-                   const protocol::endpoint& multicastEndpoint);
+  MulticastUdpFace(const protocol::endpoint& multicastGroup, const FaceUri& localUri,
+                   protocol::socket recvSocket, protocol::socket sendSocket);
 
   const protocol::endpoint&
   getMulticastGroup() const;
@@ -61,7 +59,7 @@
 
 private:
   protocol::endpoint m_multicastGroup;
-  shared_ptr<protocol::socket> m_sendSocket;
+  protocol::socket m_sendSocket;
 };
 
 } // namespace nfd
diff --git a/daemon/face/stream-face.hpp b/daemon/face/stream-face.hpp
index fa743de..94c339a 100644
--- a/daemon/face/stream-face.hpp
+++ b/daemon/face/stream-face.hpp
@@ -41,12 +41,8 @@
 public:
   typedef Protocol protocol;
 
-  /**
-   * \brief Create instance of StreamFace
-   */
   StreamFace(const FaceUri& remoteUri, const FaceUri& localUri,
-             const shared_ptr<typename protocol::socket>& socket,
-             bool isOnDemand);
+             typename protocol::socket socket, bool isOnDemand);
 
   // from FaceBase
   void
@@ -80,7 +76,7 @@
   deferredClose(const shared_ptr<Face>& face);
 
 protected:
-  shared_ptr<typename protocol::socket> m_socket;
+  typename protocol::socket m_socket;
 
   NFD_LOG_INCLASS_DECLARE();
 
@@ -117,19 +113,20 @@
 template<class T, class FaceBase>
 inline
 StreamFace<T, FaceBase>::StreamFace(const FaceUri& remoteUri, const FaceUri& localUri,
-                                    const shared_ptr<typename StreamFace::protocol::socket>& socket,
-                                    bool isOnDemand)
+                                    typename StreamFace::protocol::socket socket, bool isOnDemand)
   : FaceBase(remoteUri, localUri)
-  , m_socket(socket)
+  , m_socket(std::move(socket))
   , m_inputBufferSize(0)
 {
   NFD_LOG_FACE_INFO("Creating face");
 
   this->setOnDemand(isOnDemand);
-  StreamFaceValidator<T, FaceBase>::validateSocket(*socket);
+  StreamFaceValidator<T, FaceBase>::validateSocket(m_socket);
 
-  m_socket->async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE), 0,
-                          bind(&StreamFace<T, FaceBase>::handleReceive, this, _1, _2));
+  m_socket.async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
+                         bind(&StreamFace<T, FaceBase>::handleReceive, this,
+                              boost::asio::placeholders::error,
+                              boost::asio::placeholders::bytes_transferred));
 }
 
 
@@ -190,7 +187,7 @@
 inline void
 StreamFace<T, U>::close()
 {
-  if (!m_socket->is_open())
+  if (!m_socket.is_open())
     return;
 
   NFD_LOG_FACE_INFO("Closing face");
@@ -207,7 +204,7 @@
       error == boost::asio::error::shut_down)             // after shutdown() is called
     return;
 
-  if (!m_socket->is_open())
+  if (!m_socket.is_open())
     {
       this->fail("Connection closed");
       return;
@@ -228,9 +225,10 @@
 inline void
 StreamFace<T, U>::sendFromQueue()
 {
-  const Block& block = this->m_sendQueue.front();
-  boost::asio::async_write(*this->m_socket, boost::asio::buffer(block),
-                           bind(&StreamFace<T, U>::handleSend, this, _1, _2));
+  boost::asio::async_write(m_socket, boost::asio::buffer(m_sendQueue.front()),
+                           bind(&StreamFace<T, U>::handleSend, this,
+                                boost::asio::placeholders::error,
+                                boost::asio::placeholders::bytes_transferred));
 }
 
 template<class T, class U>
@@ -305,9 +303,11 @@
         }
     }
 
-  m_socket->async_receive(boost::asio::buffer(m_inputBuffer + m_inputBufferSize,
-                                              ndn::MAX_NDN_PACKET_SIZE - m_inputBufferSize), 0,
-                          bind(&StreamFace<T, U>::handleReceive, this, _1, _2));
+  m_socket.async_receive(boost::asio::buffer(m_inputBuffer + m_inputBufferSize,
+                                             ndn::MAX_NDN_PACKET_SIZE - m_inputBufferSize),
+                         bind(&StreamFace<T, U>::handleReceive, this,
+                              boost::asio::placeholders::error,
+                              boost::asio::placeholders::bytes_transferred));
 }
 
 template<class T, class U>
@@ -320,8 +320,8 @@
   // so that no further sends or receives are possible.
   // Use the non-throwing variants and ignore errors, if any.
   boost::system::error_code error;
-  m_socket->cancel(error);
-  m_socket->shutdown(protocol::socket::shutdown_both, error);
+  m_socket.cancel(error);
+  m_socket.shutdown(protocol::socket::shutdown_both, error);
 
   // ensure that the Face object is alive at least until all pending
   // handlers are dispatched
@@ -331,7 +331,7 @@
   // Some bug or feature of Boost.Asio (see http://redmine.named-data.net/issues/1856):
   //
   // When shutdownSocket is called from within a socket event (e.g., from handleReceive),
-  // m_socket->shutdown() does not trigger the cancellation of the handleSend callback.
+  // m_socket.shutdown() does not trigger the cancellation of the handleSend callback.
   // Instead, handleSend is invoked as nothing bad happened.
   //
   // In order to prevent the assertion in handleSend from failing, we clear the queue
@@ -353,7 +353,7 @@
 
   // use the non-throwing variant and ignore errors, if any
   boost::system::error_code error;
-  m_socket->close(error);
+  m_socket.close(error);
 }
 
 } // namespace nfd
diff --git a/daemon/face/tcp-channel.cpp b/daemon/face/tcp-channel.cpp
index 637cfa3..b46e92c 100644
--- a/daemon/face/tcp-channel.cpp
+++ b/daemon/face/tcp-channel.cpp
@@ -34,8 +34,9 @@
 using namespace boost::asio;
 
 TcpChannel::TcpChannel(const tcp::Endpoint& localEndpoint)
-  : m_acceptor(getGlobalIoService())
-  , m_localEndpoint(localEndpoint)
+  : m_localEndpoint(localEndpoint)
+  , m_acceptor(getGlobalIoService())
+  , m_acceptSocket(getGlobalIoService())
 {
   setUri(FaceUri(m_localEndpoint));
 }
@@ -74,11 +75,10 @@
     return;
   }
 
-  shared_ptr<ip::tcp::socket> clientSocket =
-    make_shared<ip::tcp::socket>(ref(getGlobalIoService()));
+  auto clientSocket = make_shared<ip::tcp::socket>(ref(getGlobalIoService()));
 
   scheduler::EventId connectTimeoutEvent = scheduler::schedule(timeout,
-      bind(&TcpChannel::handleConnectTimeout, this, clientSocket, onConnectFailed));
+    bind(&TcpChannel::handleConnectTimeout, this, clientSocket, onConnectFailed));
 
   clientSocket->async_connect(remoteEndpoint,
                               bind(&TcpChannel::handleConnect, this,
@@ -94,38 +94,39 @@
 }
 
 void
-TcpChannel::createFace(const shared_ptr<ip::tcp::socket>& socket,
+TcpChannel::createFace(ip::tcp::socket socket,
                        const FaceCreatedCallback& onFaceCreated,
                        bool isOnDemand)
 {
-  tcp::Endpoint remoteEndpoint = socket->remote_endpoint();
-
   shared_ptr<Face> face;
+  tcp::Endpoint remoteEndpoint = socket.remote_endpoint();
 
   auto it = m_channelFaces.find(remoteEndpoint);
-  if (it == m_channelFaces.end())
-    {
-      if (socket->local_endpoint().address().is_loopback())
-        face = make_shared<TcpLocalFace>(socket, isOnDemand);
-      else
-        face = make_shared<TcpFace>(socket, isOnDemand);
+  if (it == m_channelFaces.end()) {
+    tcp::Endpoint localEndpoint = socket.local_endpoint();
 
-      face->onFail.connectSingleShot([this, remoteEndpoint] (const std::string&) {
-        NFD_LOG_TRACE("Erasing " << remoteEndpoint << " from channel face map");
-        m_channelFaces.erase(remoteEndpoint);
-      });
+    if (localEndpoint.address().is_loopback() &&
+        remoteEndpoint.address().is_loopback())
+      face = make_shared<TcpLocalFace>(FaceUri(remoteEndpoint), FaceUri(localEndpoint),
+                                       std::move(socket), isOnDemand);
+    else
+      face = make_shared<TcpFace>(FaceUri(remoteEndpoint), FaceUri(localEndpoint),
+                                  std::move(socket), isOnDemand);
 
-      m_channelFaces[remoteEndpoint] = face;
-    }
-  else
-    {
-      // we've already created a a face for this endpoint, just reuse it
-      face = it->second;
+    face->onFail.connectSingleShot([this, remoteEndpoint] (const std::string&) {
+      NFD_LOG_TRACE("Erasing " << remoteEndpoint << " from channel face map");
+      m_channelFaces.erase(remoteEndpoint);
+    });
+    m_channelFaces[remoteEndpoint] = face;
+  }
+  else {
+    // we already have a face for this endpoint, just reuse it
+    face = it->second;
 
-      boost::system::error_code error;
-      socket->shutdown(ip::tcp::socket::shutdown_both, error);
-      socket->close(error);
-    }
+    boost::system::error_code error;
+    socket.shutdown(ip::tcp::socket::shutdown_both, error);
+    socket.close(error);
+  }
 
   // Need to invoke the callback regardless of whether or not we have already created
   // the face so that control responses and such can be sent.
@@ -136,17 +137,13 @@
 TcpChannel::accept(const FaceCreatedCallback& onFaceCreated,
                    const ConnectFailedCallback& onAcceptFailed)
 {
-  auto socket = make_shared<ip::tcp::socket>(ref(getGlobalIoService()));
-
-  m_acceptor.async_accept(*socket,
-                          bind(&TcpChannel::handleAccept, this,
-                               boost::asio::placeholders::error,
-                               socket, onFaceCreated, onAcceptFailed));
+  m_acceptor.async_accept(m_acceptSocket, bind(&TcpChannel::handleAccept, this,
+                                               boost::asio::placeholders::error,
+                                               onFaceCreated, onAcceptFailed));
 }
 
 void
 TcpChannel::handleAccept(const boost::system::error_code& error,
-                         const shared_ptr<boost::asio::ip::tcp::socket>& socket,
                          const FaceCreatedCallback& onFaceCreated,
                          const ConnectFailedCallback& onAcceptFailed)
 {
@@ -160,12 +157,12 @@
     return;
   }
 
-  NFD_LOG_DEBUG("[" << m_localEndpoint << "] Connection from " << socket->remote_endpoint());
+  NFD_LOG_DEBUG("[" << m_localEndpoint << "] Connection from " << m_acceptSocket.remote_endpoint());
+
+  createFace(std::move(m_acceptSocket), onFaceCreated, true);
 
   // prepare accepting the next connection
   accept(onFaceCreated, onAcceptFailed);
-
-  createFace(socket, onFaceCreated, true);
 }
 
 void
@@ -189,9 +186,10 @@
     if (error == boost::asio::error::operation_aborted) // when the socket is closed by someone
       return;
 
+    NFD_LOG_WARN("[" << m_localEndpoint << "] Connect failed: " << error.message());
+
     socket->close();
 
-    NFD_LOG_DEBUG("[" << m_localEndpoint << "] Connect failed: " << error.message());
     if (onConnectFailed)
       onConnectFailed(error.message());
     return;
@@ -199,7 +197,7 @@
 
   NFD_LOG_DEBUG("[" << m_localEndpoint << "] Connected to " << socket->remote_endpoint());
 
-  createFace(socket, onFaceCreated, false);
+  createFace(std::move(*socket), onFaceCreated, false);
 }
 
 void
diff --git a/daemon/face/tcp-channel.hpp b/daemon/face/tcp-channel.hpp
index ba59dbe..5b5505a 100644
--- a/daemon/face/tcp-channel.hpp
+++ b/daemon/face/tcp-channel.hpp
@@ -88,7 +88,7 @@
 
 private:
   void
-  createFace(const shared_ptr<boost::asio::ip::tcp::socket>& socket,
+  createFace(boost::asio::ip::tcp::socket socket,
              const FaceCreatedCallback& onFaceCreated,
              bool isOnDemand);
 
@@ -98,7 +98,6 @@
 
   void
   handleAccept(const boost::system::error_code& error,
-               const shared_ptr<boost::asio::ip::tcp::socket>& socket,
                const FaceCreatedCallback& onFaceCreated,
                const ConnectFailedCallback& onConnectFailed);
 
@@ -116,8 +115,9 @@
 private:
   std::map<tcp::Endpoint, shared_ptr<Face>> m_channelFaces;
 
-  boost::asio::ip::tcp::acceptor m_acceptor;
   tcp::Endpoint m_localEndpoint;
+  boost::asio::ip::tcp::acceptor m_acceptor;
+  boost::asio::ip::tcp::socket m_acceptSocket;
 };
 
 inline bool
diff --git a/daemon/face/tcp-face.cpp b/daemon/face/tcp-face.cpp
index 6428b03..39ebe04 100644
--- a/daemon/face/tcp-face.cpp
+++ b/daemon/face/tcp-face.cpp
@@ -32,18 +32,15 @@
                                                 TcpLocalFace::protocol, LocalFace,
                                                 "TcpLocalFace");
 
-TcpFace::TcpFace(const shared_ptr<TcpFace::protocol::socket>& socket, bool isOnDemand)
-  : StreamFace<protocol>(FaceUri(socket->remote_endpoint()),
-                         FaceUri(socket->local_endpoint()),
-                         socket, isOnDemand)
+TcpFace::TcpFace(const FaceUri& remoteUri, const FaceUri& localUri,
+                 protocol::socket socket, bool isOnDemand)
+  : StreamFace<protocol>(remoteUri, localUri, std::move(socket), isOnDemand)
 {
 }
 
-TcpLocalFace::TcpLocalFace(const shared_ptr<TcpLocalFace::protocol::socket>& socket,
-                           bool isOnDemand)
-  : StreamFace<protocol, LocalFace>(FaceUri(socket->remote_endpoint()),
-                                    FaceUri(socket->local_endpoint()),
-                                    socket, isOnDemand)
+TcpLocalFace::TcpLocalFace(const FaceUri& remoteUri, const FaceUri& localUri,
+                           protocol::socket socket, bool isOnDemand)
+  : StreamFace<protocol, LocalFace>(remoteUri, localUri, std::move(socket), isOnDemand)
 {
 }
 
diff --git a/daemon/face/tcp-face.hpp b/daemon/face/tcp-face.hpp
index e4427de..f77b72d 100644
--- a/daemon/face/tcp-face.hpp
+++ b/daemon/face/tcp-face.hpp
@@ -36,8 +36,8 @@
 class TcpFace : public StreamFace<boost::asio::ip::tcp>
 {
 public:
-  TcpFace(const shared_ptr<protocol::socket>& socket,
-          bool isOnDemand);
+  TcpFace(const FaceUri& remoteUri, const FaceUri& localUri,
+          protocol::socket socket, bool isOnDemand);
 };
 
 
@@ -49,8 +49,8 @@
 class TcpLocalFace : public StreamFace<boost::asio::ip::tcp, LocalFace>
 {
 public:
-  TcpLocalFace(const shared_ptr<protocol::socket>& socket,
-               bool isOnDemand);
+  TcpLocalFace(const FaceUri& remoteUri, const FaceUri& localUri,
+               protocol::socket socket, bool isOnDemand);
 };
 
 
diff --git a/daemon/face/udp-channel.cpp b/daemon/face/udp-channel.cpp
index bd860cc..c0d0d3c 100644
--- a/daemon/face/udp-channel.cpp
+++ b/daemon/face/udp-channel.cpp
@@ -36,25 +36,10 @@
 UdpChannel::UdpChannel(const udp::Endpoint& localEndpoint,
                        const time::seconds& timeout)
   : m_localEndpoint(localEndpoint)
-  , m_isListening(false)
+  , m_socket(getGlobalIoService())
   , m_idleFaceTimeout(timeout)
 {
   setUri(FaceUri(m_localEndpoint));
-
-  m_socket = make_shared<ip::udp::socket>(ref(getGlobalIoService()));
-  m_socket->open(m_localEndpoint.protocol());
-  m_socket->set_option(ip::udp::socket::reuse_address(true));
-  if (m_localEndpoint.address().is_v6())
-    m_socket->set_option(ip::v6_only(true));
-
-  try {
-    m_socket->bind(m_localEndpoint);
-  }
-  catch (const boost::system::system_error& e) {
-    // bind failed, so the socket is useless now
-    m_socket->close();
-    throw Error("bind failed: " + std::string(e.what()));
-  }
 }
 
 void
@@ -65,14 +50,19 @@
     NFD_LOG_WARN("[" << m_localEndpoint << "] Already listening");
     return;
   }
-  m_isListening = true;
 
-  m_socket->async_receive_from(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
-                               m_newRemoteEndpoint,
-                               bind(&UdpChannel::handleNewPeer, this,
-                                    boost::asio::placeholders::error,
-                                    boost::asio::placeholders::bytes_transferred,
-                                    onFaceCreated, onReceiveFailed));
+  m_socket.open(m_localEndpoint.protocol());
+  m_socket.set_option(ip::udp::socket::reuse_address(true));
+  if (m_localEndpoint.address().is_v6())
+    m_socket.set_option(ip::v6_only(true));
+
+  m_socket.bind(m_localEndpoint);
+  m_socket.async_receive_from(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
+                              m_remoteEndpoint,
+                              bind(&UdpChannel::handleNewPeer, this,
+                                   boost::asio::placeholders::error,
+                                   boost::asio::placeholders::bytes_transferred,
+                                   onFaceCreated, onReceiveFailed));
 }
 
 void
@@ -80,34 +70,20 @@
                     const FaceCreatedCallback& onFaceCreated,
                     const ConnectFailedCallback& onConnectFailed)
 {
-  auto it = m_channelFaces.find(remoteEndpoint);
-  if (it != m_channelFaces.end()) {
-    it->second->setOnDemand(false);
-    onFaceCreated(it->second);
-    return;
-  }
-
-  // creating a new socket for the face that will be created soon
-  shared_ptr<ip::udp::socket> clientSocket =
-    make_shared<ip::udp::socket>(ref(getGlobalIoService()));
-
-  clientSocket->open(m_localEndpoint.protocol());
-  clientSocket->set_option(ip::udp::socket::reuse_address(true));
-
+  shared_ptr<UdpFace> face;
   try {
-    clientSocket->bind(m_localEndpoint);
-    clientSocket->connect(remoteEndpoint); //@todo connect or async_connect
-    //(since there is no handshake the connect shouldn't block). If we go for
-    //async_connect, make sure that if in the meantime we receive a UDP pkt from
-    //that endpoint nothing bad happen (it's difficult, but it could happen)
+    face = createFace(remoteEndpoint, false).second;
   }
   catch (const boost::system::system_error& e) {
-    clientSocket->close();
-    onConnectFailed("Failed to configure socket (" + std::string(e.what()) + ")");
+    NFD_LOG_WARN("[" << m_localEndpoint << "] Connect failed: " << e.what());
+    if (onConnectFailed)
+      onConnectFailed(e.what());
     return;
   }
 
-  createFace(clientSocket, onFaceCreated, false);
+  // Need to invoke the callback regardless of whether or not we had already
+  // created the face so that control responses and such can be sent
+  onFaceCreated(face);
 }
 
 size_t
@@ -116,42 +92,34 @@
   return m_channelFaces.size();
 }
 
-shared_ptr<UdpFace>
-UdpChannel::createFace(const shared_ptr<ip::udp::socket>& socket,
-                       const FaceCreatedCallback& onFaceCreated,
-                       bool isOnDemand)
+std::pair<bool, shared_ptr<UdpFace>>
+UdpChannel::createFace(const udp::Endpoint& remoteEndpoint, bool isOnDemand)
 {
-  udp::Endpoint remoteEndpoint = socket->remote_endpoint();
-
-  shared_ptr<UdpFace> face;
-
   auto it = m_channelFaces.find(remoteEndpoint);
-  if (it == m_channelFaces.end())
-    {
-      face = make_shared<UdpFace>(socket, isOnDemand, m_idleFaceTimeout);
+  if (it != m_channelFaces.end()) {
+    // we already have a face for this endpoint, just reuse it
+    if (!isOnDemand)
+      // only on-demand -> non-on-demand transition is allowed
+      it->second->setOnDemand(false);
+    return {false, it->second};
+  }
 
-      face->onFail.connectSingleShot([this, remoteEndpoint] (const std::string&) {
-        NFD_LOG_TRACE("Erasing " << remoteEndpoint << " from channel face map");
-        m_channelFaces.erase(remoteEndpoint);
-      });
+  // else, create a new face
+  ip::udp::socket socket(getGlobalIoService(), m_localEndpoint.protocol());
+  socket.set_option(ip::udp::socket::reuse_address(true));
+  socket.bind(m_localEndpoint);
+  socket.connect(remoteEndpoint);
 
-      m_channelFaces[remoteEndpoint] = face;
-    }
-  else
-    {
-      // we've already created a a face for this endpoint, just reuse it
-      face = it->second;
+  auto face = make_shared<UdpFace>(FaceUri(remoteEndpoint), FaceUri(m_localEndpoint),
+                                   std::move(socket), isOnDemand, m_idleFaceTimeout);
 
-      boost::system::error_code error;
-      socket->shutdown(ip::udp::socket::shutdown_both, error);
-      socket->close(error);
-    }
+  face->onFail.connectSingleShot([this, remoteEndpoint] (const std::string&) {
+    NFD_LOG_TRACE("Erasing " << remoteEndpoint << " from channel face map");
+    m_channelFaces.erase(remoteEndpoint);
+  });
+  m_channelFaces[remoteEndpoint] = face;
 
-  // Need to invoke the callback regardless of whether or not we have already created
-  // the face so that control responses and such can be sent.
-  onFaceCreated(face);
-
-  return face;
+  return {true, face};
 }
 
 void
@@ -170,52 +138,33 @@
     return;
   }
 
-  NFD_LOG_DEBUG("[" << m_localEndpoint << "] New peer " << m_newRemoteEndpoint);
+  NFD_LOG_DEBUG("[" << m_localEndpoint << "] New peer " << m_remoteEndpoint);
 
+  bool created;
   shared_ptr<UdpFace> face;
-
-  auto it = m_channelFaces.find(m_newRemoteEndpoint);
-  if (it != m_channelFaces.end()) {
-    //The face already exists.
-    //Usually this shouldn't happen, because the channel creates a Udpface
-    //as soon as it receives a pkt from a new endpoint and then the
-    //traffic is dispatched by the kernel directly to the face.
-    //However, if the node receives multiple packets from the same endpoint
-    //"at the same time", while the channel is creating the face the kernel
-    //could dispatch the other pkts to the channel because the face is not yet
-    //ready. In this case, the channel has to pass the pkt to the face
-
-    NFD_LOG_DEBUG("The creation of the face for the remote endpoint "
-                  << m_newRemoteEndpoint << " is already in progress");
-    face = it->second;
+  try {
+    std::tie(created, face) = createFace(m_remoteEndpoint, true);
   }
-  else {
-    shared_ptr<ip::udp::socket> clientSocket =
-      make_shared<ip::udp::socket>(ref(getGlobalIoService()));
-    clientSocket->open(m_localEndpoint.protocol());
-    clientSocket->set_option(ip::udp::socket::reuse_address(true));
-    clientSocket->bind(m_localEndpoint);
-
-    boost::system::error_code ec;
-    clientSocket->connect(m_newRemoteEndpoint, ec);
-    if (ec) {
-      NFD_LOG_WARN("Error while creating on-demand UDP face from " << m_newRemoteEndpoint << ": "
-                   << boost::system::system_error(ec).what());
-      return;
-    }
-
-    face = createFace(clientSocket, onFaceCreated, true);
+  catch (const boost::system::system_error& e) {
+    NFD_LOG_WARN("[" << m_localEndpoint << "] Failed to create face for peer "
+                 << m_remoteEndpoint << ": " << e.what());
+    if (onReceiveFailed)
+      onReceiveFailed(e.what());
+    return;
   }
 
+  if (created)
+    onFaceCreated(face);
+
   // dispatch the datagram to the face for processing
   face->receiveDatagram(m_inputBuffer, nBytesReceived, error);
 
-  m_socket->async_receive_from(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
-                               m_newRemoteEndpoint,
-                               bind(&UdpChannel::handleNewPeer, this,
-                                    boost::asio::placeholders::error,
-                                    boost::asio::placeholders::bytes_transferred,
-                                    onFaceCreated, onReceiveFailed));
+  m_socket.async_receive_from(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
+                              m_remoteEndpoint,
+                              bind(&UdpChannel::handleNewPeer, this,
+                                   boost::asio::placeholders::error,
+                                   boost::asio::placeholders::bytes_transferred,
+                                   onFaceCreated, onReceiveFailed));
 }
 
 } // namespace nfd
diff --git a/daemon/face/udp-channel.hpp b/daemon/face/udp-channel.hpp
index 1451713..17410dc 100644
--- a/daemon/face/udp-channel.hpp
+++ b/daemon/face/udp-channel.hpp
@@ -43,14 +43,6 @@
 {
 public:
   /**
-   * \brief Exception of UdpChannel
-   */
-  struct Error : public std::runtime_error
-  {
-    Error(const std::string& what) : runtime_error(what) {}
-  };
-
-  /**
    * \brief Create UDP channel for the local endpoint
    *
    * To enable creation of faces upon incoming connections,
@@ -99,10 +91,8 @@
   isListening() const;
 
 private:
-  shared_ptr<UdpFace>
-  createFace(const shared_ptr<boost::asio::ip::udp::socket>& socket,
-             const FaceCreatedCallback& onFaceCreated,
-             bool isOnDemand);
+  std::pair<bool, shared_ptr<UdpFace>>
+  createFace(const udp::Endpoint& remoteEndpoint, bool isOnDemand);
 
   /**
    * \brief The channel has received a new packet from a remote
@@ -120,33 +110,27 @@
   udp::Endpoint m_localEndpoint;
 
   /**
-   * \brief Endpoint used to store the information about the last new remote endpoint
+   * \brief The latest peer that started communicating with us
    */
-  udp::Endpoint m_newRemoteEndpoint;
+  udp::Endpoint m_remoteEndpoint;
 
   /**
    * \brief Socket used to "accept" new communication
-   **/
-  shared_ptr<boost::asio::ip::udp::socket> m_socket;
-
-  uint8_t m_inputBuffer[ndn::MAX_NDN_PACKET_SIZE];
-
-  /**
-   * \brief If true, it means the function listen has already been called
    */
-  bool m_isListening;
+  boost::asio::ip::udp::socket m_socket;
 
   /**
-   * \brief every time m_idleFaceTimeout expires all the idle (and on-demand)
-   *        faces will be removed
+   * \brief When this timeout expires, all idle on-demand faces will be closed
    */
   time::seconds m_idleFaceTimeout;
+
+  uint8_t m_inputBuffer[ndn::MAX_NDN_PACKET_SIZE];
 };
 
 inline bool
 UdpChannel::isListening() const
 {
-  return m_isListening;
+  return m_socket.is_open();
 }
 
 } // namespace nfd
diff --git a/daemon/face/udp-face.cpp b/daemon/face/udp-face.cpp
index 7206984..a854cc4 100644
--- a/daemon/face/udp-face.cpp
+++ b/daemon/face/udp-face.cpp
@@ -37,9 +37,10 @@
 
 NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(DatagramFace, UdpFace::protocol, "UdpFace");
 
-UdpFace::UdpFace(const shared_ptr<UdpFace::protocol::socket>& socket,
-                 bool isOnDemand, const time::seconds& idleTimeout)
-  : DatagramFace(FaceUri(socket->remote_endpoint()), FaceUri(socket->local_endpoint()), socket)
+UdpFace::UdpFace(const FaceUri& remoteUri, const FaceUri& localUri,
+                 protocol::socket socket, bool isOnDemand,
+                 const time::seconds& idleTimeout)
+  : DatagramFace(remoteUri, localUri, std::move(socket))
   , m_idleTimeout(idleTimeout)
   , m_lastIdleCheck(time::steady_clock::now())
 {
@@ -59,24 +60,17 @@
   // routers along the path to perform fragmentation as needed.
   //
   const int value = IP_PMTUDISC_DONT;
-  if (::setsockopt(socket->native_handle(), IPPROTO_IP,
-                   IP_MTU_DISCOVER, &value, sizeof(value)) < 0)
-    {
-      NFD_LOG_FACE_WARN("Failed to disable path MTU discovery: " << std::strerror(errno));
-    }
+  if (::setsockopt(m_socket.native_handle(), IPPROTO_IP,
+                   IP_MTU_DISCOVER, &value, sizeof(value)) < 0) {
+    NFD_LOG_FACE_WARN("Failed to disable path MTU discovery: " << std::strerror(errno));
+  }
 #endif
 
   if (this->isOnDemand() && m_idleTimeout > time::seconds::zero()) {
-    m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout,
-                                             bind(&UdpFace::closeIfIdle, this));
+    m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout, bind(&UdpFace::closeIfIdle, this));
   }
 }
 
-UdpFace::~UdpFace()
-{
-  scheduler::cancel(m_closeIfIdleEvent);
-}
-
 ndn::nfd::FaceStatus
 UdpFace::getFaceStatus() const
 {
@@ -118,8 +112,7 @@
       resetRecentUsage();
 
       m_lastIdleCheck = time::steady_clock::now();
-      m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout,
-                                               bind(&UdpFace::closeIfIdle, this));
+      m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout, bind(&UdpFace::closeIfIdle, this));
     }
   }
   // else do nothing and do not reschedule the event
diff --git a/daemon/face/udp-face.hpp b/daemon/face/udp-face.hpp
index e73c1e1..333bae2 100644
--- a/daemon/face/udp-face.hpp
+++ b/daemon/face/udp-face.hpp
@@ -38,10 +38,9 @@
 class UdpFace : public DatagramFace<boost::asio::ip::udp>
 {
 public:
-  UdpFace(const shared_ptr<protocol::socket>& socket,
-          bool isOnDemand, const time::seconds& idleTimeout);
-
-  ~UdpFace() DECL_OVERRIDE;
+  UdpFace(const FaceUri& remoteUri, const FaceUri& localUri,
+          protocol::socket socket, bool isOnDemand,
+          const time::seconds& idleTimeout);
 
   ndn::nfd::FaceStatus
   getFaceStatus() const DECL_OVERRIDE;
@@ -53,7 +52,7 @@
 private:
   const time::seconds m_idleTimeout;
   time::steady_clock::TimePoint m_lastIdleCheck;
-  scheduler::EventId m_closeIfIdleEvent;
+  scheduler::ScopedEventId m_closeIfIdleEvent;
 
   // friend because it needs to invoke protected Face::setOnDemand
   friend class UdpChannel;
diff --git a/daemon/face/udp-factory.cpp b/daemon/face/udp-factory.cpp
index fcf1343..ddef35e 100644
--- a/daemon/face/udp-factory.cpp
+++ b/daemon/face/udp-factory.cpp
@@ -27,8 +27,10 @@
 #include "core/global-io.hpp"
 #include "core/network-interface.hpp"
 
-#if defined(__linux__)
-#include <sys/socket.h>
+#ifdef __linux__
+#include <cerrno>       // for errno
+#include <cstring>      // for std::strerror()
+#include <sys/socket.h> // for setsockopt()
 #endif
 
 namespace nfd {
@@ -147,20 +149,20 @@
 shared_ptr<MulticastUdpFace>
 UdpFactory::createMulticastFace(const udp::Endpoint& localEndpoint,
                                 const udp::Endpoint& multicastEndpoint,
-                                const std::string& networkInterfaceName /* "" */)
+                                const std::string& networkInterfaceName/* = ""*/)
 {
-  //checking if the local and multicast endpoint are already in use for a multicast face
-  shared_ptr<MulticastUdpFace> multicastFace = findMulticastFace(localEndpoint);
-  if (static_cast<bool>(multicastFace)) {
-    if (multicastFace->getMulticastGroup() == multicastEndpoint)
-      return multicastFace;
+  // checking if the local and multicast endpoints are already in use for a multicast face
+  shared_ptr<MulticastUdpFace> face = findMulticastFace(localEndpoint);
+  if (static_cast<bool>(face)) {
+    if (face->getMulticastGroup() == multicastEndpoint)
+      return face;
     else
       throw Error("Cannot create the requested UDP multicast face, local "
                   "endpoint is already allocated for a UDP multicast face "
                   "on a different multicast group");
   }
 
-  //checking if the local endpoint is already in use for an unicast channel
+  // checking if the local endpoint is already in use for a unicast channel
   shared_ptr<UdpChannel> unicast = findChannel(localEndpoint);
   if (static_cast<bool>(unicast)) {
     throw Error("Cannot create the requested UDP multicast face, local "
@@ -186,79 +188,63 @@
                 "the multicast group given as input is not a multicast address");
   }
 
-  shared_ptr<ip::udp::socket> receiveSocket =
-    make_shared<ip::udp::socket>(ref(getGlobalIoService()));
+  ip::udp::socket receiveSocket(getGlobalIoService());
+  receiveSocket.open(multicastEndpoint.protocol());
+  receiveSocket.set_option(ip::udp::socket::reuse_address(true));
+  receiveSocket.bind(multicastEndpoint);
 
-  shared_ptr<ip::udp::socket> sendSocket =
-    make_shared<ip::udp::socket>(ref(getGlobalIoService()));
+  ip::udp::socket sendSocket(getGlobalIoService());
+  sendSocket.open(multicastEndpoint.protocol());
+  sendSocket.set_option(ip::udp::socket::reuse_address(true));
+  sendSocket.set_option(ip::multicast::enable_loopback(false));
+  sendSocket.bind(udp::Endpoint(ip::address_v4::any(), multicastEndpoint.port()));
+  if (localEndpoint.address() != ALL_V4_ENDPOINT)
+    sendSocket.set_option(ip::multicast::outbound_interface(localEndpoint.address().to_v4()));
 
-  receiveSocket->open(multicastEndpoint.protocol());
-  receiveSocket->set_option(ip::udp::socket::reuse_address(true));
-
-  sendSocket->open(multicastEndpoint.protocol());
-  sendSocket->set_option(ip::udp::socket::reuse_address(true));
-  sendSocket->set_option(ip::multicast::enable_loopback(false));
-
-  try {
-    sendSocket->bind(udp::Endpoint(ip::address_v4::any(), multicastEndpoint.port()));
-    receiveSocket->bind(multicastEndpoint);
-
-    if (localEndpoint.address() != ip::address::from_string("0.0.0.0")) {
-      sendSocket->set_option(ip::multicast::outbound_interface(localEndpoint.address().to_v4()));
-    }
-    sendSocket->set_option(ip::multicast::join_group(multicastEndpoint.address().to_v4(),
+  sendSocket.set_option(ip::multicast::join_group(multicastEndpoint.address().to_v4(),
+                                                  localEndpoint.address().to_v4()));
+  receiveSocket.set_option(ip::multicast::join_group(multicastEndpoint.address().to_v4(),
                                                      localEndpoint.address().to_v4()));
 
-    receiveSocket->set_option(ip::multicast::join_group(multicastEndpoint.address().to_v4(),
-                                                        localEndpoint.address().to_v4()));
-  }
-  catch (boost::system::system_error& e) {
-    std::stringstream msg;
-    msg << "Failed to properly configure the socket, check the address (" << e.what() << ")";
-    throw Error(msg.str());
-  }
-
-#if defined(__linux__)
-  //On linux system, if there are more than one MulticastUdpFace for the same multicast group but
-  //bound on different network interfaces, the socket has to be bound with the specific interface
-  //using SO_BINDTODEVICE, otherwise the face will receive packets also from other interfaces.
-  //Without SO_BINDTODEVICE every MulticastUdpFace that have joined the same multicast group
-  //on different interfaces will receive the same packet.
-  //This applies only on linux, for OS X the ip::multicast::join_group is enough to get
-  //the desired behaviour
+#ifdef __linux__
+  /*
+   * On Linux, if there is more than one MulticastUdpFace for the same multicast
+   * group but they are bound to different network interfaces, the socket needs
+   * to be bound to the specific interface using SO_BINDTODEVICE, otherwise the
+   * face will receive all packets sent to the other interfaces as well.
+   * This happens only on Linux. On OS X, the ip::multicast::join_group option
+   * is enough to get the desired behaviour.
+   */
   if (!networkInterfaceName.empty()) {
-    if (::setsockopt(receiveSocket->native_handle(), SOL_SOCKET, SO_BINDTODEVICE,
-                     networkInterfaceName.c_str(), networkInterfaceName.size()+1) == -1){
-      throw Error("Cannot bind multicast face to " + networkInterfaceName
-                  + " make sure you have CAP_NET_RAW capability" );
+    if (::setsockopt(receiveSocket.native_handle(), SOL_SOCKET, SO_BINDTODEVICE,
+                     networkInterfaceName.c_str(), networkInterfaceName.size() + 1) < 0) {
+      throw Error("Cannot bind multicast face to " + networkInterfaceName +
+                  ": " + std::strerror(errno));
     }
   }
-
 #endif
 
-  multicastFace = make_shared<MulticastUdpFace>(receiveSocket, sendSocket,
-                                                localEndpoint, multicastEndpoint);
+  face = make_shared<MulticastUdpFace>(multicastEndpoint, FaceUri(localEndpoint),
+                                       std::move(receiveSocket), std::move(sendSocket));
 
-  multicastFace->onFail.connectSingleShot(bind(&UdpFactory::afterFaceFailed, this, localEndpoint));
+  face->onFail.connectSingleShot([this, localEndpoint] (const std::string& reason) {
+    m_multicastFaces.erase(localEndpoint);
+  });
+  m_multicastFaces[localEndpoint] = face;
 
-  m_multicastFaces[localEndpoint] = multicastFace;
-
-  return multicastFace;
+  return face;
 }
 
 shared_ptr<MulticastUdpFace>
 UdpFactory::createMulticastFace(const std::string& localIp,
                                 const std::string& multicastIp,
                                 const std::string& multicastPort,
-                                const std::string& networkInterfaceName /* "" */)
+                                const std::string& networkInterfaceName/* = ""*/)
 {
-  using namespace boost::asio::ip;
-  udp::Endpoint localEndpoint(address::from_string(localIp),
+  udp::Endpoint localEndpoint(ip::address::from_string(localIp),
                               boost::lexical_cast<uint16_t>(multicastPort));
-
-  udp::Endpoint multicastEndpoint(address::from_string(multicastIp),
+  udp::Endpoint multicastEndpoint(ip::address::from_string(multicastIp),
                                   boost::lexical_cast<uint16_t>(multicastPort));
-
   return createMulticastFace(localEndpoint, multicastEndpoint, networkInterfaceName);
 }
 
@@ -268,6 +254,7 @@
                        const FaceConnectFailedCallback& onConnectFailed)
 {
   BOOST_ASSERT(uri.isCanonical());
+
   boost::asio::ip::address ipAddress = boost::asio::ip::address::from_string(uri.getHost());
   udp::Endpoint endpoint(ipAddress, boost::lexical_cast<uint16_t>(uri.getPort()));
 
@@ -276,15 +263,13 @@
     return;
   }
 
-  if (m_prohibitedEndpoints.find(endpoint) != m_prohibitedEndpoints.end())
-    {
-      onConnectFailed("Requested endpoint is prohibited "
-                      "(reserved by this NFD or disallowed by face management protocol)");
-      return;
-    }
+  if (m_prohibitedEndpoints.find(endpoint) != m_prohibitedEndpoints.end()) {
+    onConnectFailed("Requested endpoint is prohibited "
+                    "(reserved by this NFD or disallowed by face management protocol)");
+    return;
+  }
 
   // very simple logic for now
-
   for (ChannelMap::iterator channel = m_channels.begin();
        channel != m_channels.end();
        ++channel)
@@ -296,6 +281,7 @@
       return;
     }
   }
+
   onConnectFailed("No channels available to connect to " +
                   boost::lexical_cast<std::string>(endpoint));
 }
@@ -320,17 +306,10 @@
     return shared_ptr<MulticastUdpFace>();
 }
 
-void
-UdpFactory::afterFaceFailed(udp::Endpoint& endpoint)
-{
-  NFD_LOG_DEBUG("afterFaceFailed: " << endpoint);
-  m_multicastFaces.erase(endpoint);
-}
-
-std::list<shared_ptr<const Channel> >
+std::list<shared_ptr<const Channel>>
 UdpFactory::getChannels() const
 {
-  std::list<shared_ptr<const Channel> > channels;
+  std::list<shared_ptr<const Channel>> channels;
   for (ChannelMap::const_iterator i = m_channels.begin(); i != m_channels.end(); ++i)
     {
       channels.push_back(i->second);
@@ -339,6 +318,4 @@
   return channels;
 }
 
-
-
 } // namespace nfd
diff --git a/daemon/face/udp-factory.hpp b/daemon/face/udp-factory.hpp
index cfbd077..e59275d 100644
--- a/daemon/face/udp-factory.hpp
+++ b/daemon/face/udp-factory.hpp
@@ -30,10 +30,9 @@
 #include "udp-channel.hpp"
 #include "multicast-udp-face.hpp"
 
-
 namespace nfd {
 
-// @todo The multicast support for ipv6 must be implemented
+/// @todo IPv6 multicast support not implemented
 
 class UdpFactory : public ProtocolFactory
 {
@@ -51,7 +50,7 @@
     }
   };
 
-  typedef std::map< udp::Endpoint, shared_ptr<MulticastUdpFace> > MulticastFaceMap;
+  typedef std::map<udp::Endpoint, shared_ptr<MulticastUdpFace>> MulticastFaceMap;
 
   explicit
   UdpFactory(const std::string& defaultPort = "6363");
@@ -143,13 +142,13 @@
                       const std::string& multicastPort,
                       const std::string& networkInterfaceName = "");
 
-  // from Factory
+  // from ProtocolFactory
   virtual void
   createFace(const FaceUri& uri,
              const FaceCreatedCallback& onCreated,
              const FaceConnectFailedCallback& onConnectFailed);
 
-  virtual std::list<shared_ptr<const Channel> >
+  virtual std::list<shared_ptr<const Channel>>
   getChannels() const;
 
   /**
@@ -159,7 +158,6 @@
   getMulticastFaces() const;
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
-
   void
   prohibitEndpoint(const udp::Endpoint& endpoint);
 
@@ -183,7 +181,6 @@
   shared_ptr<UdpChannel>
   findChannel(const udp::Endpoint& localEndpoint);
 
-
   /**
    * \brief Look up multicast UdpFace using specified local endpoint
    *
@@ -196,7 +193,7 @@
   findMulticastFace(const udp::Endpoint& localEndpoint);
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
-  typedef std::map< udp::Endpoint, shared_ptr<UdpChannel> > ChannelMap;
+  typedef std::map<udp::Endpoint, shared_ptr<UdpChannel>> ChannelMap;
 
   ChannelMap m_channels;
   MulticastFaceMap m_multicastFaces;
@@ -205,14 +202,12 @@
   std::set<udp::Endpoint> m_prohibitedEndpoints;
 };
 
-
 inline const UdpFactory::MulticastFaceMap&
 UdpFactory::getMulticastFaces() const
 {
   return m_multicastFaces;
 }
 
-
 } // namespace nfd
 
 #endif // NFD_DAEMON_FACE_UDP_FACTORY_HPP
diff --git a/daemon/face/unix-stream-channel.cpp b/daemon/face/unix-stream-channel.cpp
index 52df192..ece6d0e 100644
--- a/daemon/face/unix-stream-channel.cpp
+++ b/daemon/face/unix-stream-channel.cpp
@@ -34,11 +34,10 @@
 
 NFD_LOG_INIT("UnixStreamChannel");
 
-using namespace boost::asio::local;
-
 UnixStreamChannel::UnixStreamChannel(const unix_stream::Endpoint& endpoint)
-  : m_acceptor(getGlobalIoService())
-  , m_endpoint(endpoint)
+  : m_endpoint(endpoint)
+  , m_acceptor(getGlobalIoService())
+  , m_socket(getGlobalIoService())
 {
   setUri(FaceUri(m_endpoint));
 }
@@ -72,7 +71,7 @@
 
   if (type == fs::socket_file) {
     boost::system::error_code error;
-    stream_protocol::socket socket(getGlobalIoService());
+    boost::asio::local::stream_protocol::socket socket(getGlobalIoService());
     socket.connect(m_endpoint, error);
     NFD_LOG_TRACE("[" << m_endpoint << "] connect() on existing socket file returned: "
                   + error.message());
@@ -106,20 +105,16 @@
 }
 
 void
-UnixStreamChannel::accept(const FaceCreatedCallback &onFaceCreated,
-                          const ConnectFailedCallback &onAcceptFailed)
+UnixStreamChannel::accept(const FaceCreatedCallback& onFaceCreated,
+                          const ConnectFailedCallback& onAcceptFailed)
 {
-  auto socket = make_shared<stream_protocol::socket>(ref(getGlobalIoService()));
-
-  m_acceptor.async_accept(*socket,
-                          bind(&UnixStreamChannel::handleAccept, this,
-                               boost::asio::placeholders::error,
-                               socket, onFaceCreated, onAcceptFailed));
+  m_acceptor.async_accept(m_socket, bind(&UnixStreamChannel::handleAccept, this,
+                                         boost::asio::placeholders::error,
+                                         onFaceCreated, onAcceptFailed));
 }
 
 void
 UnixStreamChannel::handleAccept(const boost::system::error_code& error,
-                                const shared_ptr<stream_protocol::socket>& socket,
                                 const FaceCreatedCallback& onFaceCreated,
                                 const ConnectFailedCallback& onAcceptFailed)
 {
@@ -135,11 +130,13 @@
 
   NFD_LOG_DEBUG("[" << m_endpoint << "] Incoming connection");
 
+  auto remoteUri = FaceUri::fromFd(m_socket.native_handle());
+  auto localUri = FaceUri(m_socket.local_endpoint());
+  auto face = make_shared<UnixStreamFace>(remoteUri, localUri, std::move(m_socket));
+  onFaceCreated(face);
+
   // prepare accepting the next connection
   accept(onFaceCreated, onAcceptFailed);
-
-  shared_ptr<UnixStreamFace> face = make_shared<UnixStreamFace>(socket);
-  onFaceCreated(face);
 }
 
 } // namespace nfd
diff --git a/daemon/face/unix-stream-channel.hpp b/daemon/face/unix-stream-channel.hpp
index c90dcb0..06be812 100644
--- a/daemon/face/unix-stream-channel.hpp
+++ b/daemon/face/unix-stream-channel.hpp
@@ -85,13 +85,13 @@
 
   void
   handleAccept(const boost::system::error_code& error,
-               const shared_ptr<boost::asio::local::stream_protocol::socket>& socket,
                const FaceCreatedCallback& onFaceCreated,
                const ConnectFailedCallback& onAcceptFailed);
 
 private:
-  boost::asio::local::stream_protocol::acceptor m_acceptor;
   unix_stream::Endpoint m_endpoint;
+  boost::asio::local::stream_protocol::acceptor m_acceptor;
+  boost::asio::local::stream_protocol::socket m_socket;
 };
 
 inline bool
diff --git a/daemon/face/unix-stream-face.cpp b/daemon/face/unix-stream-face.cpp
index 60b2236..41ef68b 100644
--- a/daemon/face/unix-stream-face.cpp
+++ b/daemon/face/unix-stream-face.cpp
@@ -33,10 +33,9 @@
                                                 UnixStreamFace::protocol, LocalFace,
                                                 "UnixStreamFace");
 
-UnixStreamFace::UnixStreamFace(const shared_ptr<UnixStreamFace::protocol::socket>& socket)
-  : StreamFace<protocol, LocalFace>(FaceUri::fromFd(socket->native_handle()),
-                                    FaceUri(socket->local_endpoint()),
-                                    socket, true)
+UnixStreamFace::UnixStreamFace(const FaceUri& remoteUri, const FaceUri& localUri,
+                               protocol::socket socket)
+  : StreamFace<protocol, LocalFace>(remoteUri, localUri, std::move(socket), true)
 {
   static_assert(
     std::is_same<std::remove_cv<protocol::socket::native_handle_type>::type, int>::value,
diff --git a/daemon/face/unix-stream-face.hpp b/daemon/face/unix-stream-face.hpp
index 51482c4..c377819 100644
--- a/daemon/face/unix-stream-face.hpp
+++ b/daemon/face/unix-stream-face.hpp
@@ -40,8 +40,8 @@
 class UnixStreamFace : public StreamFace<boost::asio::local::stream_protocol, LocalFace>
 {
 public:
-  explicit
-  UnixStreamFace(const shared_ptr<protocol::socket>& socket);
+  UnixStreamFace(const FaceUri& remoteUri, const FaceUri& localUri,
+                 protocol::socket socket);
 };
 
 } // namespace nfd
diff --git a/tests/daemon/face/unix-stream.t.cpp b/tests/daemon/face/unix-stream.t.cpp
index c1ee2cb..9816729 100644
--- a/tests/daemon/face/unix-stream.t.cpp
+++ b/tests/daemon/face/unix-stream.t.cpp
@@ -35,8 +35,6 @@
 namespace nfd {
 namespace tests {
 
-using namespace boost::asio::local;
-
 #define CHANNEL_PATH1 "unix-stream-test.1.sock"
 #define CHANNEL_PATH2 "unix-stream-test.2.sock"
 
@@ -61,23 +59,17 @@
 BOOST_AUTO_TEST_CASE(GetChannels)
 {
   UnixStreamFactory factory;
-  BOOST_REQUIRE_EQUAL(factory.getChannels().empty(), true);
+  BOOST_CHECK(factory.getChannels().empty());
 
-  std::vector<shared_ptr<const Channel> > expectedChannels;
-
+  std::vector<shared_ptr<const Channel>> expectedChannels;
   expectedChannels.push_back(factory.createChannel(CHANNEL_PATH1));
   expectedChannels.push_back(factory.createChannel(CHANNEL_PATH2));
 
-  std::list<shared_ptr<const Channel> > channels = factory.getChannels();
-  for (std::list<shared_ptr<const Channel> >::const_iterator i = channels.begin();
-       i != channels.end(); ++i)
-    {
-      std::vector<shared_ptr<const Channel> >::iterator pos =
-        std::find(expectedChannels.begin(), expectedChannels.end(), *i);
-
-      BOOST_REQUIRE(pos != expectedChannels.end());
-      expectedChannels.erase(pos);
-    }
+  for (const auto& channel : factory.getChannels()) {
+    auto pos = std::find(expectedChannels.begin(), expectedChannels.end(), channel);
+    BOOST_REQUIRE(pos != expectedChannels.end());
+    expectedChannels.erase(pos);
+  }
 
   BOOST_CHECK_EQUAL(expectedChannels.size(), 0);
 }
@@ -160,6 +152,14 @@
     limitedIo.afterOp();
   }
 
+  shared_ptr<UnixStreamFace>
+  makeFace(UnixStreamFace::protocol::socket socket)
+  {
+    auto remoteUri = FaceUri::fromFd(socket.native_handle());
+    auto localUri = FaceUri(socket.local_endpoint());
+    return make_shared<UnixStreamFace>(remoteUri, localUri, std::move(socket));
+  }
+
 protected:
   LimitedIo limitedIo;
 
@@ -170,7 +170,7 @@
   std::vector<Interest> face2_receivedInterests;
   std::vector<Data> face2_receivedDatas;
 
-  std::list< shared_ptr<UnixStreamFace> > faces;
+  std::list<shared_ptr<UnixStreamFace>> faces;
 };
 
 
@@ -182,25 +182,24 @@
   channel1->listen(bind(&EndToEndFixture::channel1_onFaceCreated,   this, _1),
                    bind(&EndToEndFixture::channel1_onConnectFailed, this, _1));
 
-  shared_ptr<stream_protocol::socket> client = make_shared<stream_protocol::socket>(ref(g_io));
-  client->async_connect(stream_protocol::endpoint(CHANNEL_PATH1),
-                        bind(&EndToEndFixture::client_onConnect, this, _1));
+  UnixStreamFace::protocol::socket client(g_io);
+  client.async_connect(UnixStreamFace::protocol::endpoint(CHANNEL_PATH1),
+                       bind(&EndToEndFixture::client_onConnect, this, _1));
 
-  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(1)) == LimitedIo::EXCEED_OPS,
-                      "UnixStreamChannel error: cannot connect or cannot accept connection");
+  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(1)) == LimitedIo::EXCEED_OPS, "Connect");
 
   BOOST_REQUIRE(static_cast<bool>(face1));
   BOOST_CHECK_EQUAL(face1->isLocal(), true);
   BOOST_CHECK_EQUAL(face1->isOnDemand(), true);
   BOOST_CHECK_EQUAL(face1->isMultiAccess(), false);
   BOOST_CHECK_EQUAL(face1->getRemoteUri().getScheme(), "fd");
-  BOOST_CHECK_NO_THROW(boost::lexical_cast<int>(face1->getRemoteUri().getHost()));
+  BOOST_CHECK_NO_THROW(std::stoi(face1->getRemoteUri().getHost()));
   std::string face1localUri = face1->getLocalUri().toString();
   BOOST_CHECK_EQUAL(face1localUri.find("unix:///"), 0); // third '/' is the path separator
   BOOST_CHECK_EQUAL(face1localUri.rfind(CHANNEL_PATH1),
                     face1localUri.size() - std::string(CHANNEL_PATH1).size());
 
-  face2 = make_shared<UnixStreamFace>(client);
+  face2 = makeFace(std::move(client));
   face2->onReceiveInterest.connect(bind(&EndToEndFixture::face2_onReceiveInterest, this, _1));
   face2->onReceiveData.connect(bind(&EndToEndFixture::face2_onReceiveData, this, _1));
 
@@ -220,8 +219,7 @@
   face2->sendData    (*data2    );
   size_t nBytesSent2 = interest2->wireEncode().size() + data2->wireEncode().size() * 3;
 
-  BOOST_CHECK_MESSAGE(limitedIo.run(8, time::seconds(1)) == LimitedIo::EXCEED_OPS,
-                      "UnixStreamChannel error: cannot send or receive Interest/Data packets");
+  BOOST_CHECK_MESSAGE(limitedIo.run(8, time::seconds(1)) == LimitedIo::EXCEED_OPS, "Send/receive");
 
   BOOST_REQUIRE_EQUAL(face1_receivedInterests.size(), 1);
   BOOST_REQUIRE_EQUAL(face1_receivedDatas    .size(), 3);
@@ -259,21 +257,19 @@
   channel->listen(bind(&EndToEndFixture::channel_onFaceCreated,   this, _1),
                   bind(&EndToEndFixture::channel_onConnectFailed, this, _1));
 
-  shared_ptr<stream_protocol::socket> client1 = make_shared<stream_protocol::socket>(ref(g_io));
-  client1->async_connect(stream_protocol::endpoint(CHANNEL_PATH1),
-                         bind(&EndToEndFixture::client_onConnect, this, _1));
+  UnixStreamFace::protocol::socket client1(g_io);
+  client1.async_connect(UnixStreamFace::protocol::endpoint(CHANNEL_PATH1),
+                        bind(&EndToEndFixture::client_onConnect, this, _1));
 
-  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(1)) == LimitedIo::EXCEED_OPS,
-                      "UnixStreamChannel error: cannot connect or cannot accept connection");
+  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(1)) == LimitedIo::EXCEED_OPS, "First connect");
 
   BOOST_CHECK_EQUAL(faces.size(), 1);
 
-  shared_ptr<stream_protocol::socket> client2 = make_shared<stream_protocol::socket>(ref(g_io));
-  client2->async_connect(stream_protocol::endpoint(CHANNEL_PATH1),
-                         bind(&EndToEndFixture::client_onConnect, this, _1));
+  UnixStreamFace::protocol::socket client2(g_io);
+  client2.async_connect(UnixStreamFace::protocol::endpoint(CHANNEL_PATH1),
+                        bind(&EndToEndFixture::client_onConnect, this, _1));
 
-  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(1)) == LimitedIo::EXCEED_OPS,
-                      "UnixStreamChannel error: cannot accept multiple connections");
+  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(1)) == LimitedIo::EXCEED_OPS, "Second connect");
 
   BOOST_CHECK_EQUAL(faces.size(), 2);
 
@@ -285,7 +281,7 @@
   face1->onReceiveInterest.connect(bind(&EndToEndFixture::face1_onReceiveInterest, this, _1));
   face1->onReceiveData.connect(bind(&EndToEndFixture::face1_onReceiveData, this, _1));
 
-  face2 = make_shared<UnixStreamFace>(client2);
+  face2 = makeFace(std::move(client2));
   face2->onReceiveInterest.connect(bind(&EndToEndFixture::face2_onReceiveInterest, this, _1));
   face2->onReceiveData.connect(bind(&EndToEndFixture::face2_onReceiveData, this, _1));
 
@@ -299,8 +295,7 @@
   face2->sendInterest(*interest2);
   face2->sendData    (*data2    );
 
-  BOOST_CHECK_MESSAGE(limitedIo.run(4, time::seconds(1)) == LimitedIo::EXCEED_OPS,
-                      "UnixStreamChannel error: cannot send or receive Interest/Data packets");
+  BOOST_CHECK_MESSAGE(limitedIo.run(4, time::seconds(1)) == LimitedIo::EXCEED_OPS, "Send/receive");
 
   BOOST_REQUIRE_EQUAL(face1_receivedInterests.size(), 1);
   BOOST_REQUIRE_EQUAL(face1_receivedDatas    .size(), 1);
@@ -313,11 +308,6 @@
   BOOST_CHECK_EQUAL(face2_receivedDatas    [0].getName(), data1->getName());
 }
 
-static inline void
-noOp()
-{
-}
-
 BOOST_FIXTURE_TEST_CASE(UnixStreamFaceLocalControlHeader, EndToEndFixture)
 {
   UnixStreamFactory factory;
@@ -326,16 +316,15 @@
   channel1->listen(bind(&EndToEndFixture::channel1_onFaceCreated,   this, _1),
                    bind(&EndToEndFixture::channel1_onConnectFailed, this, _1));
 
-  shared_ptr<stream_protocol::socket> client = make_shared<stream_protocol::socket>(ref(g_io));
-  client->async_connect(stream_protocol::endpoint(CHANNEL_PATH1),
-                        bind(&EndToEndFixture::client_onConnect, this, _1));
+  UnixStreamFace::protocol::socket client(g_io);
+  client.async_connect(UnixStreamFace::protocol::endpoint(CHANNEL_PATH1),
+                       bind(&EndToEndFixture::client_onConnect, this, _1));
 
-  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(1)) == LimitedIo::EXCEED_OPS,
-                      "UnixStreamChannel error: cannot connect or cannot accept connection");
+  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(1)) == LimitedIo::EXCEED_OPS, "Connect");
 
   BOOST_REQUIRE(static_cast<bool>(face1));
 
-  face2 = make_shared<UnixStreamFace>(client);
+  face2 = makeFace(std::move(client));
   face2->onReceiveInterest.connect(bind(&EndToEndFixture::face2_onReceiveInterest, this, _1));
   face2->onReceiveData.connect(bind(&EndToEndFixture::face2_onReceiveData, this, _1));
 
@@ -358,18 +347,14 @@
 
   interest1->setIncomingFaceId(11);
   interest1->setNextHopFaceId(111);
-
   face1->sendInterest(*interest1);
 
   data1->setIncomingFaceId(22);
   data1->getLocalControlHeader().setNextHopFaceId(222);
-
   face1->sendData(*data1);
 
-  //
-
   BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(1)) == LimitedIo::EXCEED_OPS,
-                      "UnixStreamChannel error: cannot send or receive Interest/Data packets");
+                      "Regular send/receive");
 
   BOOST_REQUIRE_EQUAL(face2_receivedInterests.size(), 1);
   BOOST_REQUIRE_EQUAL(face2_receivedDatas    .size(), 1);
@@ -381,33 +366,41 @@
   BOOST_CHECK_EQUAL(face2_receivedDatas[0].getLocalControlHeader().hasIncomingFaceId(), false);
   BOOST_CHECK_EQUAL(face2_receivedDatas[0].getLocalControlHeader().hasNextHopFaceId(), false);
 
+  face1->close();
+  face1.reset();
+
   ////////////////////////////////////////////////////////
 
-  using namespace boost::asio;
+  client.async_connect(UnixStreamFace::protocol::endpoint(CHANNEL_PATH1),
+                       bind(&EndToEndFixture::client_onConnect, this, _1));
 
-  std::vector<const_buffer> interestWithHeader;
-  Block iHeader  = interest1->getLocalControlHeader().wireEncode(*interest1,
-    ndn::nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID |
-    ndn::nfd::LocalControlHeader::ENCODE_NEXT_HOP);
+  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(1)) == LimitedIo::EXCEED_OPS, "Connect");
+
+  BOOST_REQUIRE(static_cast<bool>(face1));
+  face1->setLocalControlHeaderFeature(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID);
+  face1->setLocalControlHeaderFeature(LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID);
+
+  Block iHeader = interest1->getLocalControlHeader()
+                  .wireEncode(*interest1, ndn::nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID |
+                                          ndn::nfd::LocalControlHeader::ENCODE_NEXT_HOP);
   Block iPayload = interest1->wireEncode();
-  interestWithHeader.push_back(buffer(iHeader.wire(),  iHeader.size()));
-  interestWithHeader.push_back(buffer(iPayload.wire(), iPayload.size()));
 
-  std::vector<const_buffer> dataWithHeader;
-  Block dHeader  = data1->getLocalControlHeader().wireEncode(*data1,
-    ndn::nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID |
-    ndn::nfd::LocalControlHeader::ENCODE_NEXT_HOP);
+  Block dHeader = data1->getLocalControlHeader()
+                  .wireEncode(*data1, ndn::nfd::LocalControlHeader::ENCODE_INCOMING_FACE_ID |
+                                      ndn::nfd::LocalControlHeader::ENCODE_NEXT_HOP);
   Block dPayload = data1->wireEncode();
-  dataWithHeader.push_back(buffer(dHeader.wire(),  dHeader.size()));
-  dataWithHeader.push_back(buffer(dPayload.wire(), dPayload.size()));
 
-  //
-
-  client->async_send(interestWithHeader, bind(&noOp));
-  client->async_send(dataWithHeader, bind(&noOp));
+  client.async_send(std::vector<boost::asio::const_buffer>{iHeader, iPayload},
+                    [] (const boost::system::error_code& error, size_t nBytesSent) {
+                      BOOST_CHECK_MESSAGE(!error, error.message());
+                    });
+  client.async_send(std::vector<boost::asio::const_buffer>{dHeader, dPayload},
+                    [] (const boost::system::error_code& error, size_t nBytesSent) {
+                      BOOST_CHECK_MESSAGE(!error, error.message());
+                    });
 
   BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(1)) == LimitedIo::EXCEED_OPS,
-                      "UnixStreamChannel error: cannot send or receive Interest/Data packets");
+                      "Send/receive with LocalControlHeader");
 
   BOOST_REQUIRE_EQUAL(face1_receivedInterests.size(), 1);
   BOOST_REQUIRE_EQUAL(face1_receivedDatas    .size(), 1);
@@ -489,15 +482,13 @@
   channel->listen(bind(&SimpleEndToEndFixture::onFaceCreated,   this, _1),
                   bind(&SimpleEndToEndFixture::onConnectFailed, this, _1));
 
-  DummyStreamSender<stream_protocol, Dataset> sender;
-  sender.start(stream_protocol::endpoint(CHANNEL_PATH1));
+  DummyStreamSender<UnixStreamFace::protocol, Dataset> sender;
+  sender.start(UnixStreamFace::protocol::endpoint(CHANNEL_PATH1));
 
-  BOOST_CHECK_MESSAGE(limitedIo.run(LimitedIo::UNLIMITED_OPS,
-                                    time::seconds(1)) == LimitedIo::EXCEED_TIME,
+  BOOST_CHECK_MESSAGE(limitedIo.run(LimitedIo::UNLIMITED_OPS, time::seconds(1)) == LimitedIo::EXCEED_TIME,
                       "Exception thrown for " + Dataset::getName());
 }
 
-
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace tests