transport: Implementation of semi-async UNIX transport (for TLV format only)

This implementation uses boost::asio to simplify all the implementation.

- connect and send operations are sync
- receive operation is async

Change-Id: If21147fbb579dc073c385a0f3a2aeef2d83fab04
diff --git a/Makefile.am b/Makefile.am
index 4134735..d6ae92b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -125,9 +125,8 @@
   src/security/policy/self-verify-policy-manager.cpp \
   src/security/security-exception.cpp \
   src/security/signature/sha256-with-rsa-handler.cpp \
-  src/transport/tcp-transport.cpp \
   src/transport/transport.cpp \
-  src/transport/udp-transport.cpp \
+  src/transport/unix-transport.cpp \
   src/util/blob-stream.hpp \
   src/util/blob.cpp \
   src/util/changed-event.cpp \
diff --git a/include/ndn-cpp/transport/unix-transport.hpp b/include/ndn-cpp/transport/unix-transport.hpp
new file mode 100644
index 0000000..bb77bb4
--- /dev/null
+++ b/include/ndn-cpp/transport/unix-transport.hpp
@@ -0,0 +1,66 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Jeff Thompson <jefft0@remap.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_UDPTRANSPORT_HPP
+#define NDN_UDPTRANSPORT_HPP
+
+#include <string>
+#include "transport.hpp"
+
+namespace ndn {
+  
+class UnixTransport : public Transport {
+public:
+  UnixTransport(const std::string &unixSocket = "/tmp/.ndnd.sock");
+  ~UnixTransport();
+
+  /**
+   * Connect according to the info in ConnectionInfo, and processEvents() will use elementListener.
+   * @param connectionInfo A reference to a TcpTransport::ConnectionInfo.
+   * @param elementListener Not a shared_ptr because we assume that it will remain valid during the life of this object.
+   */
+  virtual void 
+  connect(ElementListener& elementListener);
+  
+  /**
+   * Set data to the host
+   * @param data A pointer to the buffer of data to send.
+   * @param dataLength The number of bytes in data.
+   */
+  virtual void 
+  send(const uint8_t *data, size_t dataLength);
+
+  /**
+   * Process any data to receive.  For each element received, call elementListener.onReceivedElement.
+   * This is non-blocking and will return immediately if there is no data to receive.
+   * You should normally not call this directly since it is called by Face.processEvents.
+   * @throw This may throw an exception for reading data or in the callback for processing the data.  If you
+   * call this from an main event loop, you may want to catch and log/disregard all exceptions.
+   */
+  virtual void 
+  processEvents();
+  
+  virtual bool 
+  getIsConnected();
+
+  /**
+   * Close the connection to the host.
+   */
+  virtual void 
+  close();
+  
+private:
+  std::string unixSocket_;
+  bool isConnected_;
+
+  class Impl;
+  std::auto_ptr<Impl> impl_;
+};
+
+}
+
+#endif
diff --git a/src/transport/unix-transport.cpp b/src/transport/unix-transport.cpp
new file mode 100644
index 0000000..603f5e3
--- /dev/null
+++ b/src/transport/unix-transport.cpp
@@ -0,0 +1,128 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Jeff Thompson <jefft0@remap.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#include <stdexcept>
+#include <stdlib.h>
+
+#include <ndn-cpp/face.hpp>
+#include <ndn-cpp/transport/unix-transport.hpp>
+
+#include <boost/asio.hpp>
+#include <boost/bind.hpp>
+
+using namespace std;
+typedef boost::asio::local::datagram_protocol protocol;
+
+namespace ndn {
+
+const size_t MAX_LENGTH = 9000;
+
+class UnixTransport::Impl
+{
+public:
+  Impl() : socket_(io_)
+  {
+  }
+
+  bool
+  connect(const std::string &unixSocket, ElementListener& elementListener)
+  {
+    socket_.open();
+    socket_.connect(protocol::endpoint(unixSocket));
+    // socket_.async_connect(protocol::endpoint(unixSocket));
+
+    socket_.async_receive(boost::asio::buffer(inputBuffer_, MAX_LENGTH), 0,
+                          boost::bind(&Impl::handle_async_receive, this, _1, _2));
+
+    return true;
+  }
+
+  void 
+  send(const uint8_t *data, size_t dataLength)
+  {
+    socket_.send(boost::asio::buffer(data, dataLength));
+  }
+
+  void
+  processEvents()
+  {
+    io_.poll();
+    // from boost docs:
+    // The poll() function runs handlers that are ready to run, without blocking, until the io_service has been stopped or there are no more ready handlers.
+  }
+
+  void
+  handle_async_receive(const boost::system::error_code& error, std::size_t bytes_recvd)
+  {
+    if (!error && bytes_recvd > 0)
+      {
+        // inputBuffer_ has bytes_recvd received bytes of data
+      }
+
+    socket_.async_receive(boost::asio::buffer(inputBuffer_, MAX_LENGTH), 0,
+                          boost::bind(&Impl::handle_async_receive, this, _1, _2));
+  }
+  
+  void 
+  close()
+  {
+    socket_.close();
+  }
+  
+private:
+  boost::asio::io_service io_;
+
+  protocol::socket socket_;
+
+  uint8_t inputBuffer_[MAX_LENGTH];
+};
+
+UnixTransport::UnixTransport(const std::string &unixSocket/* = "/tmp/.ndnd.sock"*/) 
+  : unixSocket_(unixSocket)
+  , isConnected_(false)
+  , impl_(new UnixTransport::Impl())
+{
+}
+
+UnixTransport::~UnixTransport()
+{
+}
+
+void 
+UnixTransport::connect(ElementListener& elementListener)
+{
+  if (impl_->connect(unixSocket_, elementListener))
+    {
+      isConnected_ = true;
+    }
+}
+
+void 
+UnixTransport::send(const uint8_t *data, size_t dataLength)
+{
+  impl_->send(data, dataLength);
+}
+
+void 
+UnixTransport::processEvents()
+{
+  impl_->processEvents();
+}
+
+bool 
+UnixTransport::getIsConnected()
+{
+  return isConnected_;
+}
+
+void 
+UnixTransport::close()
+{
+  impl_->close();
+}
+
+}