mgmt: add face/list support and general purpose data segementer

refs: #1245

Change-Id: I3769941022b7ed6e2a8d39622032e4e16909f645
diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp
index 701bddd..bf31a10 100644
--- a/daemon/mgmt/face-manager.cpp
+++ b/daemon/mgmt/face-manager.cpp
@@ -9,7 +9,6 @@
 #include "core/face-uri.hpp"
 #include "core/network-interface.hpp"
 #include "fw/face-table.hpp"
-
 #include "face/tcp-factory.hpp"
 #include "face/udp-factory.hpp"
 
@@ -25,7 +24,7 @@
 
 NFD_LOG_INIT("FaceManager");
 
-const Name FaceManager::COMMAND_PREFIX = "/localhost/nfd/faces";
+const Name FaceManager::COMMAND_PREFIX("/localhost/nfd/faces");
 
 const size_t FaceManager::COMMAND_UNSIGNED_NCOMPS =
   FaceManager::COMMAND_PREFIX.size() +
@@ -36,28 +35,44 @@
   FaceManager::COMMAND_UNSIGNED_NCOMPS +
   4; // (timestamp, nonce, signed info tlv, signature tlv)
 
-const FaceManager::VerbAndProcessor FaceManager::COMMAND_VERBS[] =
+const FaceManager::SignedVerbAndProcessor FaceManager::SIGNED_COMMAND_VERBS[] =
   {
-    VerbAndProcessor(
+    SignedVerbAndProcessor(
                      Name::Component("create"),
                      &FaceManager::createFace
                      ),
 
-    VerbAndProcessor(
+    SignedVerbAndProcessor(
                      Name::Component("destroy"),
                      &FaceManager::destroyFace
                      ),
   };
 
+const FaceManager::UnsignedVerbAndProcessor FaceManager::UNSIGNED_COMMAND_VERBS[] =
+  {
+    UnsignedVerbAndProcessor(
+                             Name::Component("list"),
+                             &FaceManager::listFaces
+                             ),
+  };
+
+const Name FaceManager::LIST_COMMAND_PREFIX("/localhost/nfd/faces/list");
+const size_t FaceManager::LIST_COMMAND_NCOMPS = LIST_COMMAND_PREFIX.size();
+
 
 
 FaceManager::FaceManager(FaceTable& faceTable,
                          shared_ptr<InternalFace> face)
   : ManagerBase(face, FACE_MANAGER_PRIVILEGE)
   , m_faceTable(faceTable)
-  , m_verbDispatch(COMMAND_VERBS,
-                   COMMAND_VERBS +
-                   (sizeof(COMMAND_VERBS) / sizeof(VerbAndProcessor)))
+  , m_statusPublisher(m_faceTable, m_face, LIST_COMMAND_PREFIX)
+  , m_signedVerbDispatch(SIGNED_COMMAND_VERBS,
+                   SIGNED_COMMAND_VERBS +
+                   (sizeof(SIGNED_COMMAND_VERBS) / sizeof(SignedVerbAndProcessor)))
+  , m_unsignedVerbDispatch(UNSIGNED_COMMAND_VERBS,
+                   UNSIGNED_COMMAND_VERBS +
+                   (sizeof(UNSIGNED_COMMAND_VERBS) / sizeof(UnsignedVerbAndProcessor)))
+
 {
   face->setInterestFilter("/localhost/nfd/faces",
                           bind(&FaceManager::onFaceRequest, this, _2));
@@ -487,26 +502,32 @@
 {
   const Name& command = request.getName();
   const size_t commandNComps = command.size();
+  const Name::Component& verb = command.get(COMMAND_PREFIX.size());
 
-  if (COMMAND_UNSIGNED_NCOMPS <= commandNComps &&
+  UnsignedVerbDispatchTable::const_iterator unsignedVerbProcessor = m_unsignedVerbDispatch.find(verb);
+  if (unsignedVerbProcessor != m_unsignedVerbDispatch.end())
+    {
+      NFD_LOG_INFO("command result: processing verb: " << verb);
+      (unsignedVerbProcessor->second)(this, boost::cref(request));
+    }
+  else if (COMMAND_UNSIGNED_NCOMPS <= commandNComps &&
       commandNComps < COMMAND_SIGNED_NCOMPS)
     {
       NFD_LOG_INFO("command result: unsigned verb: " << command);
       sendResponse(command, 401, "Signature required");
-
-      return;
     }
   else if (commandNComps < COMMAND_SIGNED_NCOMPS ||
            !COMMAND_PREFIX.isPrefixOf(command))
     {
       NFD_LOG_INFO("command result: malformed");
       sendResponse(command, 400, "Malformed command");
-      return;
     }
-
-  validate(request,
-           bind(&FaceManager::onValidatedFaceRequest, this, _1),
-           bind(&ManagerBase::onCommandValidationFailed, this, _1, _2));
+  else
+    {
+      validate(request,
+               bind(&FaceManager::onValidatedFaceRequest, this, _1),
+               bind(&ManagerBase::onCommandValidationFailed, this, _1, _2));
+    }
 }
 
 void
@@ -515,8 +536,8 @@
   const Name& command = request->getName();
   const Name::Component& verb = command.get(COMMAND_PREFIX.size());
 
-  VerbDispatchTable::const_iterator verbProcessor = m_verbDispatch.find (verb);
-  if (verbProcessor != m_verbDispatch.end())
+  SignedVerbDispatchTable::const_iterator signedVerbProcessor = m_signedVerbDispatch.find(verb);
+  if (signedVerbProcessor != m_signedVerbDispatch.end())
     {
       ndn::nfd::FaceManagementOptions options;
       if (!extractOptions(*request, options))
@@ -526,7 +547,7 @@
         }
 
       NFD_LOG_INFO("command result: processing verb: " << verb);
-      (verbProcessor->second)(this, command, options);
+      (signedVerbProcessor->second)(this, command, options);
     }
   else
     {
@@ -617,6 +638,21 @@
   sendResponse(requestName, 200, "Success");
 }
 
+void
+FaceManager::listFaces(const Interest& request)
+{
+  const Name& command = request.getName();
+  const size_t commandNComps = command.size();
 
+  if (commandNComps < LIST_COMMAND_NCOMPS ||
+      !LIST_COMMAND_PREFIX.isPrefixOf(command))
+    {
+      NFD_LOG_INFO("command result: malformed");
+      sendResponse(command, 400, "Malformed command");
+      return;
+    }
+
+  m_statusPublisher.publish();
+}
 
 } // namespace nfd
diff --git a/daemon/mgmt/face-manager.hpp b/daemon/mgmt/face-manager.hpp
index 55e4df4..4139152 100644
--- a/daemon/mgmt/face-manager.hpp
+++ b/daemon/mgmt/face-manager.hpp
@@ -12,6 +12,8 @@
 #include "mgmt/app-face.hpp"
 #include "mgmt/manager-base.hpp"
 #include "mgmt/config-file.hpp"
+#include "mgmt/face-status-publisher.hpp"
+#include "fw/face-table.hpp"
 
 #include <ndn-cpp-dev/management/nfd-face-management-options.hpp>
 #include <ndn-cpp-dev/management/nfd-control-response.hpp>
@@ -19,15 +21,16 @@
 namespace nfd {
 
 const std::string FACE_MANAGER_PRIVILEGE = "faces";
-class FaceTable;
+
 class ProtocolFactory;
 class NetworkInterfaceInfo;
 
 class FaceManager : public ManagerBase
 {
 public:
-  struct Error : public ManagerBase::Error
+  class Error : public ManagerBase::Error
   {
+  public:
     Error(const std::string& what) : ManagerBase::Error(what) {}
   };
 
@@ -49,6 +52,10 @@
   void
   onFaceRequest(const Interest& request);
 
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+  void
+  listFaces(const Interest& request);
+
 PROTECTED_WITH_TESTS_ELSE_PRIVATE:
 
   void
@@ -107,28 +114,39 @@
   typedef std::map< std::string/*protocol*/, shared_ptr<ProtocolFactory> > FactoryMap;
   FactoryMap m_factories;
   FaceTable& m_faceTable;
+  FaceStatusPublisher m_statusPublisher;
 
   typedef function<void(FaceManager*,
                         const Name&,
-                        ndn::nfd::FaceManagementOptions&)> VerbProcessor;
+                        ndn::nfd::FaceManagementOptions&)> SignedVerbProcessor;
 
-  typedef std::map<Name::Component, VerbProcessor> VerbDispatchTable;
+  typedef std::map<Name::Component, SignedVerbProcessor> SignedVerbDispatchTable;
+  typedef std::pair<Name::Component, SignedVerbProcessor> SignedVerbAndProcessor;
 
-  typedef std::pair<Name::Component, VerbProcessor> VerbAndProcessor;
+  typedef function<void(FaceManager*, const Interest&)> UnsignedVerbProcessor;
 
-  const VerbDispatchTable m_verbDispatch;
+  typedef std::map<Name::Component, UnsignedVerbProcessor> UnsignedVerbDispatchTable;
+  typedef std::pair<Name::Component, UnsignedVerbProcessor> UnsignedVerbAndProcessor;
 
-  static const Name COMMAND_PREFIX; // /localhost/nfd/fib
 
-  // number of components in an invalid, but not malformed, unsigned command.
-  // (/localhost/nfd/fib + verb + options) = 5
+  const SignedVerbDispatchTable m_signedVerbDispatch;
+  const UnsignedVerbDispatchTable m_unsignedVerbDispatch;
+
+  static const Name COMMAND_PREFIX; // /localhost/nfd/faces
+
+  // number of components in an invalid signed command (i.e. should be signed, but isn't)
+  // (/localhost/nfd/faces + verb + options) = 5
   static const size_t COMMAND_UNSIGNED_NCOMPS;
 
-  // number of components in a valid signed Interest.
+  // number of components in a valid signed command.
   // (see UNSIGNED_NCOMPS), 9 with signed Interest support.
   static const size_t COMMAND_SIGNED_NCOMPS;
 
-  static const VerbAndProcessor COMMAND_VERBS[];
+  static const SignedVerbAndProcessor SIGNED_COMMAND_VERBS[];
+  static const UnsignedVerbAndProcessor UNSIGNED_COMMAND_VERBS[];
+
+  static const Name LIST_COMMAND_PREFIX;
+  static const size_t LIST_COMMAND_NCOMPS;
 };
 
 inline bool
diff --git a/daemon/mgmt/face-status-publisher.cpp b/daemon/mgmt/face-status-publisher.cpp
new file mode 100644
index 0000000..2cf2603
--- /dev/null
+++ b/daemon/mgmt/face-status-publisher.cpp
@@ -0,0 +1,76 @@
+/* -*- 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 "face-status-publisher.hpp"
+
+namespace nfd {
+
+NFD_LOG_INIT("FaceStatusPublisher");
+
+
+FaceStatusPublisher::FaceStatusPublisher(const FaceTable& faceTable,
+                                         shared_ptr<AppFace> face,
+                                         const Name& prefix)
+  : SegmentPublisher(face, prefix)
+  , m_faceTable(faceTable)
+{
+
+}
+
+
+FaceStatusPublisher::~FaceStatusPublisher()
+{
+
+}
+
+size_t
+FaceStatusPublisher::generate(ndn::EncodingBuffer& outBuffer)
+{
+  size_t totalLength = 0;
+
+  for (FaceTable::const_iterator i = m_faceTable.begin();
+       i != m_faceTable.end();
+       ++i)
+    {
+      const shared_ptr<Face>& face = *i;
+      const FaceCounters& counters = face->getCounters();
+      const std::string uri = face->getUri().toString();
+
+      size_t statusLength = 0;
+
+      statusLength += prependNonNegativeIntegerBlock(outBuffer,
+                                                     ndn::tlv::nfd::TotalOutgoingDataCounter,
+                                                     counters.getOutData());
+
+      statusLength += prependNonNegativeIntegerBlock(outBuffer,
+                                                     ndn::tlv::nfd::TotalOutgoingInterestCounter,
+                                                     counters.getOutInterest());
+
+      statusLength += prependNonNegativeIntegerBlock(outBuffer,
+                                                     ndn::tlv::nfd::TotalIncomingDataCounter,
+                                                     counters.getInData());
+
+      statusLength += prependNonNegativeIntegerBlock(outBuffer,
+                                                     ndn::tlv::nfd::TotalIncomingInterestCounter,
+                                                     counters.getInInterest());
+
+      statusLength += prependByteArrayBlock(outBuffer,
+                                            ndn::tlv::nfd::Uri,
+                                            reinterpret_cast<const uint8_t*>(uri.c_str()),
+                                            uri.size());
+
+      statusLength += prependNonNegativeIntegerBlock(outBuffer,
+                                                     ndn::tlv::nfd::FaceId,
+                                                     face->getId());
+
+      statusLength += outBuffer.prependVarNumber(statusLength);
+      statusLength += outBuffer.prependVarNumber(ndn::tlv::nfd::FaceStatus);
+
+      totalLength += statusLength;
+    }
+  return totalLength;
+}
+
+} // namespace nfd
diff --git a/daemon/mgmt/face-status-publisher.hpp b/daemon/mgmt/face-status-publisher.hpp
new file mode 100644
index 0000000..2006462
--- /dev/null
+++ b/daemon/mgmt/face-status-publisher.hpp
@@ -0,0 +1,36 @@
+/* -*- 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_MGMT_FACE_STATUS_PUBLISHER_HPP
+#define NFD_MGMT_FACE_STATUS_PUBLISHER_HPP
+
+#include "fw/face-table.hpp"
+#include "mgmt/segment-publisher.hpp"
+
+namespace nfd {
+
+class FaceStatusPublisher : public SegmentPublisher
+{
+public:
+  FaceStatusPublisher(const FaceTable& faceTable,
+                      shared_ptr<AppFace> face,
+                      const Name& prefix);
+
+  virtual
+  ~FaceStatusPublisher();
+
+protected:
+
+  virtual size_t
+  generate(ndn::EncodingBuffer& outBuffer);
+
+private:
+  const FaceTable& m_faceTable;
+};
+
+} // namespace nfd
+
+#endif // NFD_MGMT_FACE_STATUS_PUBLISHER_HPP
diff --git a/daemon/mgmt/segment-publisher.cpp b/daemon/mgmt/segment-publisher.cpp
new file mode 100644
index 0000000..bd7d971
--- /dev/null
+++ b/daemon/mgmt/segment-publisher.cpp
@@ -0,0 +1,83 @@
+/* -*- 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 "segment-publisher.hpp"
+
+#include "common.hpp"
+#include "face/face.hpp"
+
+#include <ndn-cpp-dev/util/time.hpp>
+
+namespace nfd {
+
+NFD_LOG_INIT("SegmentPublisher");
+
+SegmentPublisher::SegmentPublisher(shared_ptr<AppFace> face,
+                                   const Name& prefix)
+  : m_face(face)
+  , m_prefix(prefix)
+{
+
+}
+
+
+SegmentPublisher::~SegmentPublisher()
+{
+
+}
+
+void
+SegmentPublisher::publish()
+{
+  Name segmentPrefix(m_prefix);
+  segmentPrefix.appendSegment(ndn::ndn_getNowMilliseconds());
+
+  static const size_t  MAX_SEGMENT_SIZE = MAX_NDN_PACKET_SIZE >> 1;
+
+  ndn::EncodingBuffer buffer;
+
+  generate(buffer);
+
+  const uint8_t* rawBuffer = buffer.buf();
+  const uint8_t* segmentBegin = rawBuffer;
+  const uint8_t* end = rawBuffer + buffer.size();
+
+  uint64_t segmentNo = 0;
+  while (segmentBegin < end)
+    {
+      const uint8_t* segmentEnd = segmentBegin + MAX_SEGMENT_SIZE;
+      if (segmentEnd > end)
+        {
+          segmentEnd = end;
+        }
+
+      Name segmentName(segmentPrefix);
+      segmentName.appendSegment(segmentNo);
+
+      shared_ptr<Data> data(make_shared<Data>(segmentName));
+      data->setContent(segmentBegin, segmentEnd - segmentBegin);
+
+      segmentBegin = segmentEnd;
+      if (segmentBegin >= end)
+        {
+          NFD_LOG_DEBUG("final block is " << segmentNo);
+          data->setFinalBlockId(segmentName[-1]);
+        }
+
+      NFD_LOG_DEBUG("publishing segment #" << segmentNo);
+      publishSegment(data);
+      segmentNo++;
+    }
+}
+
+void
+SegmentPublisher::publishSegment(shared_ptr<Data>& data)
+{
+  m_face->sign(*data);
+  m_face->put(*data);
+}
+
+} // namespace nfd
diff --git a/daemon/mgmt/segment-publisher.hpp b/daemon/mgmt/segment-publisher.hpp
new file mode 100644
index 0000000..4b5dc4f
--- /dev/null
+++ b/daemon/mgmt/segment-publisher.hpp
@@ -0,0 +1,47 @@
+/* -*- 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_MGMT_SEGMENT_PUBLISHER_HPP
+#define NFD_MGMT_SEGMENT_PUBLISHER_HPP
+
+#include "common.hpp"
+#include "mgmt/app-face.hpp"
+
+#include <ndn-cpp-dev/encoding/encoding-buffer.hpp>
+
+namespace nfd {
+
+class AppFace;
+
+class SegmentPublisher : noncopyable
+{
+public:
+  SegmentPublisher(shared_ptr<AppFace> face,
+                   const Name& prefix);
+
+  virtual
+  ~SegmentPublisher();
+
+  void
+  publish();
+
+protected:
+
+  virtual size_t
+  generate(ndn::EncodingBuffer& outBuffer) =0;
+
+private:
+  void
+  publishSegment(shared_ptr<Data>& data);
+
+private:
+  shared_ptr<AppFace> m_face;
+  const Name m_prefix;
+};
+
+} // namespace nfd
+
+#endif // NFD_MGMT_SEGMENT_PUBLISHER_HPP