face: cleanup log messages in all faces and print fail reason

Change-Id: I405198b375a0317663d29810ee87922a19edccaa
Refs: #2450
diff --git a/daemon/face/datagram-face.hpp b/daemon/face/datagram-face.hpp
index 1b534ca..339831c 100644
--- a/daemon/face/datagram-face.hpp
+++ b/daemon/face/datagram-face.hpp
@@ -27,6 +27,7 @@
 #define NFD_DAEMON_FACE_DATAGRAM_FACE_HPP
 
 #include "face.hpp"
+#include "core/global-io.hpp"
 #include "core/logger.hpp"
 
 namespace nfd {
@@ -50,18 +51,17 @@
                const shared_ptr<typename protocol::socket>& socket,
                bool isOnDemand);
 
-  virtual
-  ~DatagramFace();
+  ~DatagramFace() DECL_OVERRIDE;
 
   // from Face
-  virtual void
-  sendInterest(const Interest& interest);
+  void
+  sendInterest(const Interest& interest) DECL_OVERRIDE;
 
-  virtual void
-  sendData(const Data& data);
+  void
+  sendData(const Data& data) DECL_OVERRIDE;
 
-  virtual void
-  close();
+  void
+  close() DECL_OVERRIDE;
 
   void
   receiveDatagram(const uint8_t* buffer,
@@ -82,6 +82,9 @@
 
 protected:
   void
+  processErrorCode(const boost::system::error_code& error);
+
+  void
   handleSend(const boost::system::error_code& error,
              size_t nBytesSent,
              const Block& payload);
@@ -151,55 +154,57 @@
 
 template<class T, class U>
 inline void
-DatagramFace<T, U>::handleSend(const boost::system::error_code& error,
-                               size_t nBytesSent,
-                               const Block& payload)
-// 'payload' is unused; it's needed to retain the underlying Buffer
-{
-  if (error != 0) {
-    if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
-      return;
-
-    if (!m_socket->is_open()) {
-      fail("Tunnel closed");
-      return;
-    }
-
-    NFD_LOG_WARN("[id:" << this->getId()
-                  << ",uri:" << this->getRemoteUri()
-                  << "] Send operation failed, closing socket: "
-                  << error.category().message(error.value()));
-
-    closeSocket();
-
-    if (error == boost::asio::error::eof) {
-      fail("Tunnel closed");
-    }
-    else {
-      fail("Send operation failed, closing socket: " + error.message());
-    }
-    return;
-  }
-
-  NFD_LOG_TRACE("[id:" << this->getId()
-                << ",uri:" << this->getRemoteUri()
-                << "] Successfully sent: " << nBytesSent << " bytes");
-  this->getMutableCounters().getNOutBytes() += nBytesSent;
-}
-
-template<class T, class U>
-inline void
 DatagramFace<T, U>::close()
 {
   if (!m_socket->is_open())
     return;
 
-  NFD_LOG_INFO("[id:" << this->getId()
-               << ",uri:" << this->getRemoteUri()
-               << "] Close tunnel");
+  NFD_LOG_INFO("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
+               << "] Closing face");
 
   closeSocket();
-  fail("Close tunnel");
+  fail("Face closed");
+}
+
+template<class T, class U>
+inline void
+DatagramFace<T, U>::processErrorCode(const boost::system::error_code& error)
+{
+  if (error == boost::asio::error::operation_aborted) // when socket is closed by someone
+    return;
+
+  // this should be unnecessary, but just in case
+  if (!m_socket->is_open()) {
+    this->fail("Tunnel closed");
+    return;
+  }
+
+  if (error != boost::asio::error::eof)
+    NFD_LOG_WARN("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
+                 << "] Send or receive operation failed, closing face: "
+                 << error.message());
+
+  closeSocket();
+
+  if (error == boost::asio::error::eof)
+    this->fail("Tunnel closed");
+  else
+    this->fail("Send or receive operation failed: " + error.message());
+}
+
+template<class T, class U>
+inline void
+DatagramFace<T, U>::handleSend(const boost::system::error_code& error,
+                               size_t nBytesSent,
+                               const Block& payload)
+// 'payload' is unused; it's needed to retain the underlying Buffer
+{
+  if (error)
+    return processErrorCode(error);
+
+  NFD_LOG_TRACE("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
+                << "] Successfully sent: " << nBytesSent << " bytes");
+  this->getMutableCounters().getNOutBytes() += nBytesSent;
 }
 
 template<class T, class U>
@@ -207,8 +212,8 @@
 DatagramFace<T, U>::handleReceive(const boost::system::error_code& error,
                                   size_t nBytesReceived)
 {
-  NFD_LOG_DEBUG("handleReceive: " << nBytesReceived);
   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));
@@ -220,35 +225,10 @@
                                     size_t nBytesReceived,
                                     const boost::system::error_code& error)
 {
-  if (error != 0 || nBytesReceived == 0) {
-    if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
-      return;
+  if (error || nBytesReceived == 0)
+    return processErrorCode(error);
 
-    // this should be unnecessary, but just in case
-    if (!m_socket->is_open()) {
-      fail("Tunnel closed");
-      return;
-    }
-
-    NFD_LOG_WARN("[id:" << this->getId()
-                 << ",uri:" << this->getRemoteUri()
-                 << "] Receive operation failed: "
-                 << error.category().message(error.value()));
-
-    closeSocket();
-
-    if (error == boost::asio::error::eof) {
-      fail("Tunnel closed");
-    }
-    else {
-      fail("Receive operation failed, closing socket: " +
-             error.category().message(error.value()));
-    }
-    return;
-  }
-
-  NFD_LOG_TRACE("[id:" << this->getId()
-                << ",uri:" << this->getRemoteUri()
+  NFD_LOG_TRACE("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
                 << "] Received: " << nBytesReceived << " bytes");
   this->getMutableCounters().getNInBytes() += nBytesReceived;
 
@@ -256,8 +236,7 @@
   bool isOk = Block::fromBuffer(buffer, nBytesReceived, element);
   if (!isOk)
     {
-      NFD_LOG_WARN("[id:" << this->getId()
-                   << ",uri:" << this->getRemoteUri()
+      NFD_LOG_WARN("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
                    << "] Failed to parse incoming packet");
       // This message won't extend the face lifetime
       return;
@@ -265,8 +244,7 @@
 
   if (element.size() != nBytesReceived)
     {
-      NFD_LOG_WARN("[id:" << this->getId()
-                   << ",uri:" << this->getRemoteUri()
+      NFD_LOG_WARN("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
                    << "] Received datagram size and decoded "
                    << "element size don't match");
       // This message won't extend the face lifetime
@@ -275,8 +253,7 @@
 
   if (!this->decodeAndDispatchInput(element))
     {
-      NFD_LOG_WARN("[id:" << this->getId()
-                   << ",uri:" << this->getRemoteUri()
+      NFD_LOG_WARN("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
                    << "] Received unrecognized block of type ["
                    << element.type() << "]");
       // This message won't extend the face lifetime
@@ -286,7 +263,6 @@
   m_hasBeenUsedRecently = true;
 }
 
-
 template<class T, class U>
 inline void
 DatagramFace<T, U>::keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face)
@@ -297,12 +273,6 @@
 inline void
 DatagramFace<T, U>::closeSocket()
 {
-  NFD_LOG_DEBUG("[id:" << this->getId()
-                << ",uri:" << this->getRemoteUri()
-                << "] closeSocket");
-
-  boost::asio::io_service& io = m_socket->get_io_service();
-
   // use the non-throwing variants and ignore errors, if any
   boost::system::error_code error;
   m_socket->shutdown(protocol::socket::shutdown_both, error);
@@ -311,8 +281,8 @@
 
   // ensure that the Face object is alive at least until all pending
   // handlers are dispatched
-  io.post(bind(&DatagramFace<T, U>::keepFaceAliveUntilAllHandlersExecuted,
-               this, this->shared_from_this()));
+  getGlobalIoService().post(bind(&DatagramFace<T, U>::keepFaceAliveUntilAllHandlersExecuted,
+                                 this, this->shared_from_this()));
 }
 
 template<class T, class U>
diff --git a/daemon/face/ethernet-face.hpp b/daemon/face/ethernet-face.hpp
index cb6303b..e9f0e2a 100644
--- a/daemon/face/ethernet-face.hpp
+++ b/daemon/face/ethernet-face.hpp
@@ -64,24 +64,23 @@
                const NetworkInterfaceInfo& interface,
                const ethernet::Address& address);
 
-  virtual
-  ~EthernetFace();
+  ~EthernetFace() DECL_OVERRIDE;
 
   /// send an Interest
-  virtual void
-  sendInterest(const Interest& interest);
+  void
+  sendInterest(const Interest& interest) DECL_OVERRIDE;
 
   /// send a Data
-  virtual void
-  sendData(const Data& data);
+  void
+  sendData(const Data& data) DECL_OVERRIDE;
 
   /**
    * @brief Closes the face
    *
    * This terminates all communication on the face and triggers the onFail() event.
    */
-  virtual void
-  close();
+  void
+  close() DECL_OVERRIDE;
 
 private:
   /**
diff --git a/daemon/face/face.cpp b/daemon/face/face.cpp
index ef17d29..e45fb1b 100644
--- a/daemon/face/face.cpp
+++ b/daemon/face/face.cpp
@@ -24,7 +24,6 @@
  */
 
 #include "face.hpp"
-#include "core/logger.hpp"
 
 namespace nfd {
 
@@ -106,7 +105,7 @@
 
     return true;
   }
-  catch (tlv::Error&) {
+  catch (const tlv::Error&) {
     return false;
   }
 }
diff --git a/daemon/face/local-face.hpp b/daemon/face/local-face.hpp
index 3a0c39f..c54374c 100644
--- a/daemon/face/local-face.hpp
+++ b/daemon/face/local-face.hpp
@@ -182,7 +182,7 @@
 
     return true;
   }
-  catch (tlv::Error&) {
+  catch (const tlv::Error&) {
     return false;
   }
 }
diff --git a/daemon/face/multicast-udp-face.hpp b/daemon/face/multicast-udp-face.hpp
index 0ac857e..c08375b 100644
--- a/daemon/face/multicast-udp-face.hpp
+++ b/daemon/face/multicast-udp-face.hpp
@@ -49,14 +49,14 @@
   getMulticastGroup() const;
 
   // from Face
-  virtual void
-  sendInterest(const Interest& interest);
+  void
+  sendInterest(const Interest& interest) DECL_OVERRIDE;
 
-  virtual void
-  sendData(const Data& data);
+  void
+  sendData(const Data& data) DECL_OVERRIDE;
 
-  virtual bool
-  isMultiAccess() const;
+  bool
+  isMultiAccess() const DECL_OVERRIDE;
 
 private:
   void
diff --git a/daemon/face/null-face.hpp b/daemon/face/null-face.hpp
index 3dae571..a4e3977 100644
--- a/daemon/face/null-face.hpp
+++ b/daemon/face/null-face.hpp
@@ -39,20 +39,14 @@
   explicit
   NullFace(const FaceUri& uri = FaceUri("null://"));
 
-  virtual void
-  sendInterest(const Interest& interest);
+  void
+  sendInterest(const Interest& interest) DECL_OVERRIDE;
 
-  /// send a Data
-  virtual void
-  sendData(const Data& data);
+  void
+  sendData(const Data& data) DECL_OVERRIDE;
 
-  /** \brief Close the face
-   *
-   *  This terminates all communication on the face and cause
-   *  onFail() method event to be invoked
-   */
-  virtual void
-  close();
+  void
+  close() DECL_OVERRIDE;
 };
 
 } // namespace nfd
diff --git a/daemon/face/stream-face.hpp b/daemon/face/stream-face.hpp
index 64c1d57..255e8ee 100644
--- a/daemon/face/stream-face.hpp
+++ b/daemon/face/stream-face.hpp
@@ -28,6 +28,7 @@
 
 #include "face.hpp"
 #include "local-face.hpp"
+#include "core/global-io.hpp"
 #include "core/logger.hpp"
 
 namespace nfd {
@@ -48,18 +49,17 @@
              const shared_ptr<typename protocol::socket>& socket,
              bool isOnDemand);
 
-  virtual
-  ~StreamFace();
+  ~StreamFace() DECL_OVERRIDE;
 
-  // from Face
-  virtual void
-  sendInterest(const Interest& interest);
+  // from FaceBase
+  void
+  sendInterest(const Interest& interest) DECL_OVERRIDE;
 
-  virtual void
-  sendData(const Data& data);
+  void
+  sendData(const Data& data) DECL_OVERRIDE;
 
-  virtual void
-  close();
+  void
+  close() DECL_OVERRIDE;
 
 protected:
   void
@@ -197,12 +197,11 @@
   if (!m_socket->is_open())
     return;
 
-  NFD_LOG_INFO("[id:" << this->getId()
-               << ",uri:" << this->getRemoteUri()
-               << "] Close connection");
+  NFD_LOG_INFO("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
+               << "] Closing face");
 
   shutdownSocket();
-  this->fail("Close connection");
+  this->fail("Face closed");
 }
 
 template<class T, class U>
@@ -219,19 +218,10 @@
       return;
     }
 
-  if (error == boost::asio::error::eof)
-    {
-      NFD_LOG_INFO("[id:" << this->getId()
-                   << ",uri:" << this->getRemoteUri()
-                   << "] Connection closed");
-    }
-  else
-    {
-      NFD_LOG_WARN("[id:" << this->getId()
-                   << ",uri:" << this->getRemoteUri()
-                   << "] Send or receive operation failed, closing face: "
-                   << error.message());
-    }
+  if (error != boost::asio::error::eof)
+    NFD_LOG_WARN("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
+                 << "] Send or receive operation failed, closing face: "
+                 << error.message());
 
   shutdownSocket();
 
@@ -241,7 +231,7 @@
     }
   else
     {
-      this->fail("Send or receive operation failed, closing face: " + error.message());
+      this->fail("Send or receive operation failed: " + error.message());
     }
 }
 
@@ -264,8 +254,7 @@
 
   BOOST_ASSERT(!m_sendQueue.empty());
 
-  NFD_LOG_TRACE("[id:" << this->getId()
-                << ",uri:" << this->getRemoteUri()
+  NFD_LOG_TRACE("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
                 << "] Successfully sent: " << nBytesSent << " bytes");
   this->getMutableCounters().getNOutBytes() += nBytesSent;
 
@@ -282,8 +271,7 @@
   if (error)
     return processErrorCode(error);
 
-  NFD_LOG_TRACE("[id:" << this->getId()
-                << ",uri:" << this->getRemoteUri()
+  NFD_LOG_TRACE("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
                 << "] Received: " << nBytesReceived << " bytes");
   this->getMutableCounters().getNInBytes() += nBytesReceived;
 
@@ -305,8 +293,7 @@
 
       if (!this->decodeAndDispatchInput(element))
         {
-          NFD_LOG_WARN("[id:" << this->getId()
-                       << ",uri:" << this->getRemoteUri()
+          NFD_LOG_WARN("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
                        << "] Received unrecognized block of type ["
                        << element.type() << "]");
           // ignore unknown packet and proceed
@@ -314,13 +301,11 @@
     }
   if (!isOk && m_inputBufferSize == ndn::MAX_NDN_PACKET_SIZE && offset == 0)
     {
-      NFD_LOG_WARN("[id:" << this->getId()
-                   << ",uri:" << this->getRemoteUri()
+      NFD_LOG_WARN("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
                    << "] Failed to parse incoming packet or packet too large to process, "
-                   << "closing down the face");
+                   << "closing face");
       shutdownSocket();
-      this->fail("Failed to parse incoming packet or packet too large to process, "
-                 "closing down the face");
+      this->fail("Failed to parse incoming packet or packet too large to process");
       return;
     }
 
@@ -354,10 +339,10 @@
   m_socket->cancel(error);
   m_socket->shutdown(protocol::socket::shutdown_both, error);
 
-  boost::asio::io_service& io = m_socket->get_io_service();
   // ensure that the Face object is alive at least until all pending
   // handlers are dispatched
-  io.post(bind(&StreamFace<T, U>::deferredClose, this, this->shared_from_this()));
+  getGlobalIoService().post(bind(&StreamFace<T, U>::deferredClose,
+                                 this, this->shared_from_this()));
 
   // Some bug or feature of Boost.Asio (see http://redmine.named-data.net/issues/1856):
   //
@@ -376,8 +361,7 @@
 inline void
 StreamFace<T, U>::deferredClose(const shared_ptr<Face>& face)
 {
-  NFD_LOG_DEBUG("[id:" << this->getId()
-                << ",uri:" << this->getRemoteUri()
+  NFD_LOG_DEBUG("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
                 << "] Clearing send queue");
 
   // clear send queue
diff --git a/daemon/face/udp-face.cpp b/daemon/face/udp-face.cpp
index 17214c5..53dc374 100644
--- a/daemon/face/udp-face.cpp
+++ b/daemon/face/udp-face.cpp
@@ -27,6 +27,8 @@
 // #include "core/global-io.hpp" // for #1718 manual test below
 
 #ifdef __linux__
+#include <cerrno>       // for errno
+#include <cstring>      // for std::strerror()
 #include <netinet/in.h> // for IP_MTU_DISCOVER and IP_PMTUDISC_DONT
 #include <sys/socket.h> // for setsockopt()
 #endif
@@ -61,9 +63,8 @@
   if (::setsockopt(socket->native_handle(), IPPROTO_IP,
                    IP_MTU_DISCOVER, &value, sizeof(value)) < 0)
     {
-      NFD_LOG_WARN("[id:" << this->getId()
-                   << ",uri:" << this->getRemoteUri()
-                   << "] Failed to disable path MTU discovery");
+      NFD_LOG_WARN("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
+                   << "] Failed to disable path MTU discovery: " << std::strerror(errno));
     }
 #endif
 
@@ -81,7 +82,8 @@
 ndn::nfd::FaceStatus
 UdpFace::getFaceStatus() const
 {
-  ndn::nfd::FaceStatus status = Face::getFaceStatus();
+  auto status = Face::getFaceStatus();
+
   if (isOnDemand()) {
     time::milliseconds left = m_idleTimeout - time::duration_cast<time::milliseconds>(
       time::steady_clock::now() - m_lastIdleCheck);
@@ -95,6 +97,7 @@
       status.setExpirationPeriod(left);
     }
   }
+
   return status;
 }
 
@@ -105,12 +108,7 @@
   // (non-on-demand -> on-demand transition is not allowed)
   if (isOnDemand()) {
     if (!hasBeenUsedRecently()) {
-      // face has been idle since the last time closeIfIdle
-      // has been called. Going to close it
-      NFD_LOG_DEBUG("Found idle face id: " << getId());
-
-      NFD_LOG_INFO("[id:" << this->getId()
-                   << ",uri:" << this->getRemoteUri()
+      NFD_LOG_INFO("[id:" << this->getId() << ",uri:" << this->getRemoteUri()
                    << "] Idle for more than " << m_idleTimeout << ", closing");
       close();
 
diff --git a/daemon/face/udp-face.hpp b/daemon/face/udp-face.hpp
index b56b81d..829b3bc 100644
--- a/daemon/face/udp-face.hpp
+++ b/daemon/face/udp-face.hpp
@@ -42,11 +42,10 @@
           bool isOnDemand,
           const time::seconds& idleTimeout);
 
-  virtual
-  ~UdpFace();
+  ~UdpFace() DECL_OVERRIDE;
 
-  virtual ndn::nfd::FaceStatus
-  getFaceStatus() const;
+  ndn::nfd::FaceStatus
+  getFaceStatus() const DECL_OVERRIDE;
 
 private:
   void
diff --git a/daemon/face/websocket-face.cpp b/daemon/face/websocket-face.cpp
index 26c1a25..4875f6c 100644
--- a/daemon/face/websocket-face.cpp
+++ b/daemon/face/websocket-face.cpp
@@ -24,7 +24,6 @@
  */
 
 #include "websocket-face.hpp"
-#include "core/global-io.hpp"
 
 namespace nfd {
 
@@ -48,6 +47,7 @@
     return;
 
   this->emitSignal(onSendInterest, interest);
+
   const Block& payload = interest.wireEncode();
   this->getMutableCounters().getNOutBytes() += payload.size();
 
@@ -56,8 +56,7 @@
                   websocketpp::frame::opcode::binary);
   }
   catch (const websocketpp::lib::error_code& e) {
-    NFD_LOG_DEBUG("Failed to send Interest because: " << e
-                  << "(" << e.message() << ")");
+    NFD_LOG_WARN("Failed to send Interest: " << e << " (" << e.message() << ")");
   }
 }
 
@@ -68,6 +67,7 @@
     return;
 
   this->emitSignal(onSendData, data);
+
   const Block& payload = data.wireEncode();
   this->getMutableCounters().getNOutBytes() += payload.size();
 
@@ -76,8 +76,7 @@
                   websocketpp::frame::opcode::binary);
   }
   catch (const websocketpp::lib::error_code& e) {
-    NFD_LOG_DEBUG("Failed to send Data because: " << e
-                  << "(" << e.message() << ")");
+    NFD_LOG_WARN("Failed to send Data: " << e << " (" << e.message() << ")");
   }
 }
 
@@ -102,30 +101,29 @@
   if (msg.size() > ndn::MAX_NDN_PACKET_SIZE)
     {
       NFD_LOG_WARN("[id:" << this->getId()
-                   << "] Received WebSocket message size ["
-                   << msg.size() << "] is too big");
+                   << "] Received WebSocket message is too big (" << msg.size() << " bytes)");
       return;
     }
 
+  NFD_LOG_TRACE("[id:" << this->getId()
+                << "] Received: " << msg.size() << " bytes");
   this->getMutableCounters().getNInBytes() += msg.size();
 
   // Try to parse message data
-  bool isOk = true;
   Block element;
-  isOk = Block::fromBuffer(reinterpret_cast<const uint8_t*>(msg.c_str()), msg.size(), element);
+  bool isOk = Block::fromBuffer(reinterpret_cast<const uint8_t*>(msg.c_str()),
+                                msg.size(), element);
   if (!isOk)
     {
       NFD_LOG_WARN("[id:" << this->getId()
-                   << "] Received invalid NDN packet of length ["
-                   << msg.size() << "]");
+                   << "] Received block is invalid or too large to process");
       return;
     }
 
   if (!this->decodeAndDispatchInput(element))
     {
       NFD_LOG_WARN("[id:" << this->getId()
-                   << "] Received unrecognized block of type ["
-                   << element.type() << "]");
+                   << "] Received unrecognized TLV block of type " << element.type());
       // ignore unknown packet and proceed
     }
 }
diff --git a/daemon/face/websocket-face.hpp b/daemon/face/websocket-face.hpp
index 56dd015..711699b 100644
--- a/daemon/face/websocket-face.hpp
+++ b/daemon/face/websocket-face.hpp
@@ -55,14 +55,14 @@
                 websocketpp::connection_hdl hdl, websocket::Server& server);
 
   // from Face
-  virtual void
-  sendInterest(const Interest& interest);
+  void
+  sendInterest(const Interest& interest) DECL_OVERRIDE;
 
-  virtual void
-  sendData(const Data& data);
+  void
+  sendData(const Data& data) DECL_OVERRIDE;
 
-  virtual void
-  close();
+  void
+  close() DECL_OVERRIDE;
 
   void
   setPingEventId(scheduler::EventId& id)
@@ -70,6 +70,10 @@
     m_pingEventId = id;
   }
 
+protected:
+  // friend because it needs to invoke protected handleReceive
+  friend class WebSocketChannel;
+
   void
   handleReceive(const std::string& msg);
 
diff --git a/daemon/fw/face-table.cpp b/daemon/fw/face-table.cpp
index 1848380..0f78f74 100644
--- a/daemon/fw/face-table.cpp
+++ b/daemon/fw/face-table.cpp
@@ -87,21 +87,24 @@
 
   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));
+  face->onFail.connectSingleShot(bind(&FaceTable::remove, this, face, _1));
 
   this->onAdd(face);
 }
 
 void
-FaceTable::remove(shared_ptr<Face> face)
+FaceTable::remove(shared_ptr<Face> face, const std::string& reason)
 {
   this->onRemove(face);
 
   FaceId faceId = face->getId();
   m_faces.erase(faceId);
   face->setId(INVALID_FACEID);
-  NFD_LOG_INFO("Removed face id=" << faceId << " remote=" << face->getRemoteUri() <<
-                                                " local=" << face->getLocalUri());
+
+  NFD_LOG_INFO("Removed face id=" << faceId <<
+               " remote=" << face->getRemoteUri() <<
+               " local=" << face->getLocalUri() <<
+               " (" << reason << ")");
 
   m_forwarder.getFib().removeNextHopFromAllEntries(face);
 }
diff --git a/daemon/fw/face-table.hpp b/daemon/fw/face-table.hpp
index 435999e..67c7932 100644
--- a/daemon/fw/face-table.hpp
+++ b/daemon/fw/face-table.hpp
@@ -87,10 +87,10 @@
   void
   addImpl(shared_ptr<Face> face, FaceId faceId);
 
-  // remove is private because it's a subscriber of face.onFail event.
-  // face->close() closes a face and triggers .remove(face)
+  // remove is private because it's a handler of face.onFail signal.
+  // face->close() closes the face and triggers .remove()
   void
-  remove(shared_ptr<Face> face);
+  remove(shared_ptr<Face> face, const std::string& reason);
 
   ForwardRange
   getForwardRange() const;
diff --git a/tests/daemon/face/dummy-face.hpp b/tests/daemon/face/dummy-face.hpp
index 0158a3d..2991afb 100644
--- a/tests/daemon/face/dummy-face.hpp
+++ b/tests/daemon/face/dummy-face.hpp
@@ -49,24 +49,24 @@
   {
   }
 
-  virtual void
-  sendInterest(const Interest& interest)
+  void
+  sendInterest(const Interest& interest) DECL_OVERRIDE
   {
     this->emitSignal(onSendInterest, interest);
     m_sentInterests.push_back(interest);
     this->afterSend();
   }
 
-  virtual void
-  sendData(const Data& data)
+  void
+  sendData(const Data& data) DECL_OVERRIDE
   {
     this->emitSignal(onSendData, data);
     m_sentDatas.push_back(data);
     this->afterSend();
   }
 
-  virtual void
-  close()
+  void
+  close() DECL_OVERRIDE
   {
     this->fail("close");
   }