Merge branch for issue: #1132
diff --git a/daemon/common.hpp b/daemon/common.hpp
index 9b50fda..a98719d 100644
--- a/daemon/common.hpp
+++ b/daemon/common.hpp
@@ -14,6 +14,7 @@
 
 #include <boost/utility.hpp>
 #include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
 #include <boost/function.hpp>
 #include <boost/bind.hpp>
 #include <boost/ref.hpp>
@@ -28,6 +29,7 @@
 
 using boost::noncopyable;
 using boost::shared_ptr;
+using boost::enable_shared_from_this;
 using boost::make_shared;
 using boost::function;
 using boost::bind;
diff --git a/daemon/face/channel-factory.hpp b/daemon/face/channel-factory.hpp
new file mode 100644
index 0000000..a2d7ff9
--- /dev/null
+++ b/daemon/face/channel-factory.hpp
@@ -0,0 +1,39 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_FACE_CHANNEL_FACTORY_HPP
+#define NFD_FACE_CHANNEL_FACTORY_HPP
+
+#include "common.hpp"
+
+namespace ndn {
+
+/**
+ * \brief Base class for all channel factories
+ */
+template<class E, class C>
+class ChannelFactory
+{
+public:
+  typedef E Endpoint;
+  typedef C Channel;
+  
+  /**
+   * \brief Base class for all exceptions thrown by channel factories
+   */
+  struct Error : public std::runtime_error
+  {
+    Error(const std::string& what) : std::runtime_error(what) {}
+  };
+
+protected:
+  typedef std::map< Endpoint, shared_ptr<Channel> > ChannelMap;
+  ChannelMap m_channels;  
+};
+
+} // namespace ndn
+
+#endif // NFD_FACE_CHANNEL_FACTORY_HPP
diff --git a/daemon/face/face.hpp b/daemon/face/face.hpp
index abcb3ab..f014545 100644
--- a/daemon/face/face.hpp
+++ b/daemon/face/face.hpp
@@ -17,10 +17,12 @@
  */
 typedef int FaceId;
 
+const std::size_t MAX_NDN_PACKET_SIZE = 8800;
+
 /** \class Face
  *  \brief represents a face
  */
-class Face : noncopyable
+class Face : noncopyable, public enable_shared_from_this<Face>
 {
 public:
   Face(FaceId id);
@@ -33,14 +35,17 @@
   
   /// fires when a Data is received
   EventEmitter<const Data&> onReceiveData;
+
+  /// fires when face disconnects or fails to perform properly
+  EventEmitter<const std::string& /*reason*/> onFail;
   
   /// send an Interest
   virtual void
-  sendInterest(const Interest &interest) =0;
+  sendInterest(const Interest& interest) = 0;
   
   /// send a Data
   virtual void
-  sendData(const Data &data) =0;
+  sendData(const Data& data) = 0;
   
   /** \brief Get whether underlying communicate is up
    *  In this base class this property is always true.
diff --git a/daemon/face/stream-face.hpp b/daemon/face/stream-face.hpp
new file mode 100644
index 0000000..8fd39a1
--- /dev/null
+++ b/daemon/face/stream-face.hpp
@@ -0,0 +1,149 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_FACE_STREAM_FACE_HPP
+#define NFD_FACE_STREAM_FACE_HPP
+
+#include "face.hpp"
+
+namespace ndn {
+
+template <class T>
+class StreamFace : public Face
+{
+public:
+  typedef T protocol;
+
+  StreamFace(FaceId id,
+             const shared_ptr<typename protocol::socket>& socket);
+
+protected:
+  void
+  handleSend(const boost::system::error_code& error,
+             const Block& wire);
+
+  void
+  handleReceive(const boost::system::error_code& error,
+                std::size_t bytes_recvd);
+
+protected:
+  shared_ptr<typename protocol::socket> m_socket;
+
+private:
+  uint8_t m_inputBuffer[MAX_NDN_PACKET_SIZE];
+  std::size_t m_inputBufferSize;
+};
+
+template <class T>
+inline
+StreamFace<T>::StreamFace(FaceId id,
+                          const shared_ptr<typename StreamFace::protocol::socket>& socket)
+  : Face(id)
+  , m_socket(socket)
+{
+  m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
+                          bind(&StreamFace<T>::handleReceive, this, _1, _2));
+}
+
+
+template <class T>
+inline void
+StreamFace<T>::handleSend(const boost::system::error_code& error,
+                          const Block& wire)
+{
+  if (error) {
+    if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
+      return;
+
+    onFail("Send operation failed: " + error.category().message(error.value()));
+    m_socket->close();
+    return;
+  }
+
+  // do nothing (needed to retain validity of wire memory block
+}
+
+template <class T>
+inline void
+StreamFace<T>::handleReceive(const boost::system::error_code& error,
+                             std::size_t bytes_recvd)
+{
+  if (error || bytes_recvd == 0) {
+    if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
+      return;
+
+    onFail("Receive operation failed: " + error.category().message(error.value()));
+    m_socket->close();
+    return;
+  }
+
+  m_inputBufferSize += bytes_recvd;
+  // do magic
+
+  std::size_t offset = 0;
+  /// @todo Eliminate reliance on exceptions in this path
+  try {
+    Block element(m_inputBuffer + offset, m_inputBufferSize - offset);
+    offset += element.size();
+
+    /// @todo Ensure lazy field decoding process
+    if (element.type() == Tlv::Interest)
+      {
+        shared_ptr<Interest> i = make_shared<Interest>();
+        i->wireDecode(element);
+        onReceiveInterest(*i);
+      }
+    else if (element.type() == Tlv::Data)
+      {
+        shared_ptr<Data> d = make_shared<Data>();
+        d->wireDecode(element);
+        onReceiveData(*d);
+      }
+    // @todo Add local header support
+    // else if (element.type() == Tlv::LocalHeader)
+    //   {
+    //     shared_ptr<Interest> i = make_shared<Interest>();
+    //     i->wireDecode(element);
+    //   }
+    else
+      {
+        /// @todo Add loggin
+
+        // ignore unknown packet and proceed
+      }
+  }
+  catch(const Tlv::Error&) {
+    if (m_inputBufferSize == MAX_NDN_PACKET_SIZE && offset == 0)
+      {
+        onFail("Received input is invalid or too large to process, closing down the face");
+        m_socket->close();
+        return;
+      }
+  }
+
+  if (offset > 0)
+    {
+      if (offset != m_inputBufferSize)
+        {
+          std::copy(m_inputBuffer + offset, m_inputBuffer + m_inputBufferSize,
+                    m_inputBuffer);
+          m_inputBufferSize -= offset;
+        }
+      else
+        {
+          m_inputBufferSize = 0;
+        }
+    }
+
+  m_socket->async_receive(boost::asio::buffer(m_inputBuffer + m_inputBufferSize,
+                                              MAX_NDN_PACKET_SIZE - m_inputBufferSize), 0,
+                          bind(&StreamFace<T>::handleReceive, this, _1, _2));
+}
+
+
+} // namespace ndn
+
+#endif // NFD_FACE_STREAM_FACE_HPP
diff --git a/daemon/face/tcp-channel-factory.cpp b/daemon/face/tcp-channel-factory.cpp
new file mode 100644
index 0000000..4c6df87
--- /dev/null
+++ b/daemon/face/tcp-channel-factory.cpp
@@ -0,0 +1,56 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "tcp-channel-factory.hpp"
+
+namespace ndn {
+
+TcpChannelFactory::TcpChannelFactory(boost::asio::io_service& ioService)
+  : m_ioService(ioService)
+{
+}
+
+shared_ptr<TcpChannel>
+TcpChannelFactory::create(const tcp::Endpoint& endpoint)
+{
+  shared_ptr<TcpChannel> channel = find(endpoint);
+  if(static_cast<bool>(channel))
+    return channel;
+
+  channel = make_shared<TcpChannel>(boost::ref(m_ioService), boost::cref(endpoint));
+  m_channels[endpoint] = channel;
+  return channel;
+}
+
+shared_ptr<TcpChannel>
+TcpChannelFactory::create(const std::string& localHost, const std::string& localPort)
+{
+  using boost::asio::ip::tcp;
+  
+  tcp::resolver::query query(localHost, localPort);
+  // shared_ptr<tcp::resolver> resolver =
+  //   make_shared<tcp::resolver>(boost::ref(m_ioService));
+  tcp::resolver resolver(m_ioService);
+
+  tcp::resolver::iterator end;
+  tcp::resolver::iterator i = resolver.resolve(query);
+  if (i == end)
+    return shared_ptr<ndn::TcpChannel>();
+
+  return create(*i);
+}
+
+shared_ptr<TcpChannel>
+TcpChannelFactory::find(const tcp::Endpoint& localEndpoint)
+{
+  ChannelMap::iterator i = m_channels.find(localEndpoint);
+  if (i != m_channels.end())
+    return i->second;
+  else
+    return shared_ptr<ndn::TcpChannel>();
+}
+
+} // namespace ndn
diff --git a/daemon/face/tcp-channel-factory.hpp b/daemon/face/tcp-channel-factory.hpp
new file mode 100644
index 0000000..1baeb58
--- /dev/null
+++ b/daemon/face/tcp-channel-factory.hpp
@@ -0,0 +1,78 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_FACE_TCP_CHANNEL_FACTORY_HPP
+#define NFD_FACE_TCP_CHANNEL_FACTORY_HPP
+
+#include "channel-factory.hpp"
+#include "tcp-channel.hpp"
+
+namespace ndn {
+
+class TcpChannelFactory : public ChannelFactory<tcp::Endpoint, TcpChannel>
+{
+public:
+  /**
+   * \brief Exception of TcpChannelFactory
+   */
+  struct Error : public ChannelFactory::Error
+  {
+    Error(const std::string& what) : ChannelFactory::Error(what) {}
+  };
+
+  TcpChannelFactory(boost::asio::io_service& ioService);
+
+  /**
+   * \brief Create TCP-based channel using tcp::Endpoint
+   *
+   * tcp::Endpoint is really an alias for boost::asio::ip::tcp::endpoint.
+   *
+   * If this method called twice with the same endpoint, only one channel
+   * will be created.  The second call will just retrieve the existing
+   * channel.
+   *
+   * \returns always a valid pointer to a TcpChannel object, an exception
+   *          is thrown if it cannot be created.
+   *
+   * \throws TcpChannelFactory::Error
+   *
+   * \see http://www.boost.org/doc/libs/1_42_0/doc/html/boost_asio/reference/ip__tcp/endpoint.html
+   *      for details on ways to create tcp::Endpoint
+   */
+  shared_ptr<TcpChannel>
+  create(const tcp::Endpoint& localEndpoint);
+
+  /**
+   * \brief Create TCP-based channel using specified host and port number
+   *
+   * This method will attempt to resolve the provided host and port numbers
+   * and will throw TcpChannelFactory::Error when channel cannot be created.
+   *
+   * Note that this call will **BLOCK** until resolution is done or failed.
+   *
+   * \throws TcpChannelFactory::Error
+   */
+  shared_ptr<TcpChannel>
+  create(const std::string& localHost, const std::string& localPort);
+
+  /**
+   * \brief Look up TcpChannel using specified local endpoint
+   *
+   * \returns shared pointer to the existing TcpChannel object
+   *          or empty shared pointer when such channel does not exist 
+   *
+   * \throws never
+   */
+  shared_ptr<TcpChannel>
+  find(const tcp::Endpoint& localEndpoint);
+  
+private:
+  boost::asio::io_service& m_ioService;
+};
+
+} // namespace ndn
+
+#endif // NFD_FACE_TCP_CHANNEL_FACTORY_HPP
diff --git a/daemon/face/tcp-channel.cpp b/daemon/face/tcp-channel.cpp
new file mode 100644
index 0000000..9da453e
--- /dev/null
+++ b/daemon/face/tcp-channel.cpp
@@ -0,0 +1,196 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "tcp-channel.hpp"
+
+namespace ndn {
+
+using namespace boost::asio;
+
+TcpChannel::TcpChannel(io_service& ioService,
+                       const tcp::Endpoint& localEndpoint)
+  : m_ioService(ioService)
+  , m_localEndpoint(localEndpoint)
+{
+}
+
+void
+TcpChannel::listen(const FaceCreatedCallback& onFaceCreated,
+                   const ConnectFailedCallback& onAcceptFailed,
+                   int backlog/* = tcp::acceptor::max_connections*/)
+{
+  m_acceptor = make_shared<ip::tcp::acceptor>(boost::ref(m_ioService));
+  m_acceptor->open(m_localEndpoint.protocol());
+  m_acceptor->set_option(ip::tcp::acceptor::reuse_address(true));
+  m_acceptor->bind(m_localEndpoint);
+  m_acceptor->listen(backlog);
+
+  shared_ptr<ip::tcp::socket> clientSocket =
+    make_shared<ip::tcp::socket>(boost::ref(m_ioService));
+  m_acceptor->async_accept(*clientSocket,
+                           bind(&TcpChannel::handleConnection, this, _1,
+                                clientSocket,
+                                onFaceCreated, onAcceptFailed));
+}
+
+void
+TcpChannel::connect(const tcp::Endpoint& remoteEndpoint,
+                    const TcpChannel::FaceCreatedCallback& onFaceCreated,
+                    const TcpChannel::ConnectFailedCallback& onConnectFailed,
+                    const time::Duration& timeout/* = time::seconds(4)*/)
+{
+  ChannelFaceMap::iterator i = m_channelFaces.find(remoteEndpoint);
+  if (i != m_channelFaces.end()) {
+    onFaceCreated(i->second);
+    return;
+  }
+
+  shared_ptr<ip::tcp::socket> clientSocket =
+    make_shared<ip::tcp::socket>(boost::ref(m_ioService));
+
+  shared_ptr<monotonic_deadline_timer> connectTimeoutTimer =
+    make_shared<monotonic_deadline_timer>(boost::ref(m_ioService));
+
+  // not sure if it works. This will bind to something...
+  // Do we need reuse here too?
+  clientSocket->bind(m_localEndpoint);
+
+  clientSocket->async_connect(remoteEndpoint,
+                              bind(&TcpChannel::handleSuccessfulConnect, this, _1,
+                                   clientSocket, connectTimeoutTimer,
+                                   onFaceCreated, onConnectFailed));
+
+  connectTimeoutTimer->expires_from_now(timeout);
+  connectTimeoutTimer->async_wait(bind(&TcpChannel::handleFailedConnect, this, _1,
+                                       clientSocket, connectTimeoutTimer,
+                                       onConnectFailed));
+}
+
+void
+TcpChannel::connect(const std::string& remoteHost, const std::string& remotePort,
+                    const TcpChannel::FaceCreatedCallback& onFaceCreated,
+                    const TcpChannel::ConnectFailedCallback& onConnectFailed,
+                    const time::Duration& timeout/* = time::seconds(4)*/)
+{
+  shared_ptr<ip::tcp::socket> clientSocket =
+    make_shared<ip::tcp::socket>(boost::ref(m_ioService));
+
+  shared_ptr<monotonic_deadline_timer> connectTimeoutTimer =
+    make_shared<monotonic_deadline_timer>(boost::ref(m_ioService));
+
+  // not sure if it works. This will bind to something...
+  // Do we need reuse here too?
+  clientSocket->bind(m_localEndpoint);
+
+  ip::tcp::resolver::query query(remoteHost, remotePort);
+  shared_ptr<ip::tcp::resolver> resolver =
+    make_shared<ip::tcp::resolver>(boost::ref(m_ioService));
+
+  resolver->async_resolve(query,
+                          bind(&TcpChannel::handleEndpointResoution, this, _1, _2,
+                               clientSocket, connectTimeoutTimer,
+                               onFaceCreated, onConnectFailed));
+
+  connectTimeoutTimer->expires_from_now(timeout);
+  connectTimeoutTimer->async_wait(bind(&TcpChannel::handleFailedConnect, this, _1,
+                                       clientSocket, connectTimeoutTimer,
+                                       onConnectFailed));
+}
+
+
+void
+TcpChannel::handleConnection(const boost::system::error_code& error,
+                             const shared_ptr<ip::tcp::socket>& socket,
+                             const FaceCreatedCallback& onFaceCreated,
+                             const ConnectFailedCallback& onConnectFailed)
+{
+  if (error) {
+    if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
+      return;
+
+    /// \todo Log the error
+    onConnectFailed("Connect to remote endpoint failed: " +
+                    error.category().message(error.value()));
+    return;
+  }
+
+  /**
+   * \todo Remove FaceId from here
+   */
+  shared_ptr<TcpFace> face = make_shared<TcpFace>(1, boost::cref(socket));
+  onFaceCreated(face);
+
+  tcp::Endpoint remoteEndpoint = socket->remote_endpoint();
+  m_channelFaces[remoteEndpoint] = face;
+}
+
+void
+TcpChannel::handleSuccessfulConnect(const boost::system::error_code& error,
+                                    const shared_ptr<ip::tcp::socket>& socket,
+                                    const shared_ptr<monotonic_deadline_timer>& timer,
+                                    const FaceCreatedCallback& onFaceCreated,
+                                    const ConnectFailedCallback& onConnectFailed)
+{
+  timer->cancel();
+
+  if (error) {
+    if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
+      return;
+
+    socket->close();
+    onConnectFailed("Connect to remote endpoint failed: " +
+                    error.category().message(error.value()));
+    return;
+  }
+
+  handleConnection(error, socket, onFaceCreated, onConnectFailed);
+}
+
+void
+TcpChannel::handleFailedConnect(const boost::system::error_code& error,
+                                const shared_ptr<ip::tcp::socket>& socket,
+                                const shared_ptr<monotonic_deadline_timer>& timer,
+                                const ConnectFailedCallback& onConnectFailed)
+{
+  if (error) { // e.g., cancelled
+    return;
+  }
+
+  onConnectFailed("Connect to remote endpoint timed out: " +
+                  error.category().message(error.value()));
+  socket->close(); // abort the connection
+}
+
+void
+TcpChannel::handleEndpointResoution(const boost::system::error_code& error,
+                                    ip::tcp::resolver::iterator remoteEndpoint,
+                                    const shared_ptr<boost::asio::ip::tcp::socket>& socket,
+                                    const shared_ptr<boost::asio::monotonic_deadline_timer>& timer,
+                                    const FaceCreatedCallback& onFaceCreated,
+                                    const ConnectFailedCallback& onConnectFailed)
+{
+  if (error ||
+      remoteEndpoint == ip::tcp::resolver::iterator())
+    {
+      if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
+        return;
+
+      socket->close();
+      timer->cancel();
+      onConnectFailed("Remote endpoint hostname or port cannot be resolved: " +
+                      error.category().message(error.value()));
+      return;
+    }
+
+  // got endpoint, now trying to connect (only try the first resolution option)
+  socket->async_connect(*remoteEndpoint,
+                        bind(&TcpChannel::handleSuccessfulConnect, this, _1,
+                             socket, timer,
+                             onFaceCreated, onConnectFailed));
+}
+
+
+} // namespace ndn
diff --git a/daemon/face/tcp-channel.hpp b/daemon/face/tcp-channel.hpp
new file mode 100644
index 0000000..8536203
--- /dev/null
+++ b/daemon/face/tcp-channel.hpp
@@ -0,0 +1,130 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_FACE_TCP_CHANNEL_HPP
+#define NFD_FACE_TCP_CHANNEL_HPP
+
+#include "common.hpp"
+#include "core/monotonic_deadline_timer.hpp"
+#include "tcp-face.hpp"
+
+namespace tcp {
+typedef boost::asio::ip::tcp::endpoint Endpoint;
+} // namespace tcp
+
+namespace ndn {
+
+/**
+ * \brief Class implementing TCP-based channel to create faces
+ *
+ * Channel can create faces as a response to incoming TCP
+ * connections (TcpChannel::listen needs to be called for that
+ * to work) or explicitly after using TcpChannel::connect method.
+ */
+class TcpChannel // : protected SessionBasedChannel
+{
+public:
+  /**
+   * \brief Prototype for the callback called when face is created
+   *        (as a response to incoming connection or after connection
+   *        is established)
+   */
+  typedef function<void(const shared_ptr<TcpFace>& newFace)> FaceCreatedCallback;
+
+  /**
+   * \brief Prototype for the callback that is called when face is failed to
+   *        get created
+   */
+  typedef function<void(const std::string& reason)> ConnectFailedCallback;
+  
+  /**
+   * \brief Create TCP channel for the local endpoint
+   *
+   * To enable creation faces upon incoming connections,
+   * one needs to explicitly call TcpChannel::listen method.
+   */
+  TcpChannel(boost::asio::io_service& ioService,
+             const tcp::Endpoint& localEndpoint);
+
+  /**
+   * \brief Enable listening on the local endpoint, accept connections,
+   *        and create faces when remote host makes a connection
+   * \param backlog The maximum length of the queue of pending incoming
+   *        connections
+   */
+  void
+  listen(const FaceCreatedCallback& onFaceCreated,
+         const ConnectFailedCallback& onAcceptFailed,
+         int backlog = boost::asio::ip::tcp::acceptor::max_connections);
+
+  /**
+   * \brief Create a face by establishing connection to remote endpoint
+   */
+  void
+  connect(const tcp::Endpoint& remoteEndpoint,
+          const FaceCreatedCallback& onFaceCreated,
+          const ConnectFailedCallback& onConnectFailed,
+          const time::Duration& timeout = time::seconds(4));
+
+  /**
+   * \brief Create a face by establishing connection to the specified
+   *        remote host and remote port
+   *
+   * This method will never block and will return immediately. All
+   * necessary hostname and port resolution and connection will happen
+   * in asynchronous mode.
+   *
+   * If connection cannot be established within specified timeout, it
+   * will be aborted.
+   */
+  void
+  connect(const std::string& remoteHost, const std::string& remotePort,
+          const FaceCreatedCallback& onFaceCreated,
+          const ConnectFailedCallback& onConnectFailed,
+          const time::Duration& timeout = time::seconds(4));
+  
+private:
+  void
+  handleConnection(const boost::system::error_code& error,
+                   const shared_ptr<boost::asio::ip::tcp::socket>& socket,
+                   const FaceCreatedCallback& onFaceCreated,
+                   const ConnectFailedCallback& onConnectFailed);
+
+  void
+  handleSuccessfulConnect(const boost::system::error_code& error,
+                          const shared_ptr<boost::asio::ip::tcp::socket>& socket,
+                          const shared_ptr<boost::asio::monotonic_deadline_timer>& timer,
+                          const FaceCreatedCallback& onFaceCreated,
+                          const ConnectFailedCallback& onConnectFailed);
+  
+  void
+  handleFailedConnect(const boost::system::error_code& error,
+                      const shared_ptr<boost::asio::ip::tcp::socket>& socket,
+                      const shared_ptr<boost::asio::monotonic_deadline_timer>& timer,
+                      const ConnectFailedCallback& onConnectFailed);
+
+  void
+  handleEndpointResoution(const boost::system::error_code& error,
+                          boost::asio::ip::tcp::resolver::iterator remoteEndpoint,
+                          const shared_ptr<boost::asio::ip::tcp::socket>& socket,
+                          const shared_ptr<boost::asio::monotonic_deadline_timer>& timer,
+                          const FaceCreatedCallback& onFaceCreated,
+                          const ConnectFailedCallback& onConnectFailed);
+  
+private:
+  boost::asio::io_service& m_ioService;
+  tcp::Endpoint m_localEndpoint;
+
+  typedef std::map< tcp::Endpoint, shared_ptr<TcpFace> > ChannelFaceMap;
+  ChannelFaceMap m_channelFaces;
+
+  bool isListening;
+  shared_ptr<boost::asio::ip::tcp::acceptor> m_acceptor;
+};
+
+} // namespace ndn
+ 
+#endif // NFD_FACE_TCP_CHANNEL_HPP
diff --git a/daemon/face/tcp-face.cpp b/daemon/face/tcp-face.cpp
new file mode 100644
index 0000000..eb3ac94
--- /dev/null
+++ b/daemon/face/tcp-face.cpp
@@ -0,0 +1,37 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "tcp-face.hpp"
+
+namespace ndn {
+
+TcpFace::TcpFace(FaceId id,
+                 const shared_ptr<TcpFace::protocol::socket>& socket)
+  : StreamFace<protocol>(id, socket)
+{
+}
+
+void
+TcpFace::sendInterest(const Interest& interest)
+{
+  m_socket->async_send(boost::asio::buffer(interest.wireEncode().wire(),
+                                           interest.wireEncode().size()),
+                       bind(&TcpFace::handleSend, this, _1, interest.wireEncode()));
+
+  // anything else should be done here?
+}
+
+void
+TcpFace::sendData(const Data& data)
+{
+  m_socket->async_send(boost::asio::buffer(data.wireEncode().wire(),
+                                           data.wireEncode().size()),
+                       bind(&TcpFace::handleSend, this, _1, data.wireEncode()));
+
+  // anything else should be done here?
+}
+
+} // namespace ndn
diff --git a/daemon/face/tcp-face.hpp b/daemon/face/tcp-face.hpp
new file mode 100644
index 0000000..3d2bb53
--- /dev/null
+++ b/daemon/face/tcp-face.hpp
@@ -0,0 +1,37 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_FACE_TCP_FACE_HPP
+#define NFD_FACE_TCP_FACE_HPP
+
+#include "stream-face.hpp"
+
+namespace ndn
+{
+
+/**
+ * \brief Implementation of Face abstraction that uses TCP
+ *        as underlying transport mechanism
+ */
+class TcpFace : public StreamFace<boost::asio::ip::tcp>
+{
+public:
+  typedef boost::asio::ip::tcp protocol;
+
+  TcpFace(FaceId id,
+          const shared_ptr<protocol::socket>& socket);
+
+  // from Face
+  virtual void
+  sendInterest(const Interest& interest);
+
+  virtual void
+  sendData(const Data& data);
+};
+
+} // namespace ndn
+
+#endif // NFD_FACE_TCP_FACE_HPP