management: Adding nfd::FaceEventNotification data structure

Change-Id: I5b5b8b0f86a5ccd4ed82561aaf87118400a0ba33
Refs: #1244
diff --git a/src/encoding/tlv-nfd.hpp b/src/encoding/tlv-nfd.hpp
index cb89709..7a84951 100644
--- a/src/encoding/tlv-nfd.hpp
+++ b/src/encoding/tlv-nfd.hpp
@@ -45,7 +45,7 @@
   TotalIncomingDataCounter     = 144,
   TotalOutgoingInterestCounter = 146,
   TotalOutgoingDataCounter     = 147,
-  FaceEvent                    = 192,
+  FaceEventNotification        = 192,
   FaceEventKind                = 193,
 
   // Forwarder status
diff --git a/src/management/nfd-face-event-notification.hpp b/src/management/nfd-face-event-notification.hpp
new file mode 100644
index 0000000..4a299d3
--- /dev/null
+++ b/src/management/nfd-face-event-notification.hpp
@@ -0,0 +1,190 @@
+/* -*- 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 NDN_MANAGEMENT_NFD_FACE_EVENT_NOTIFICATION_HPP
+#define NDN_MANAGEMENT_NFD_FACE_EVENT_NOTIFICATION_HPP
+
+#include "../encoding/encoding-buffer.hpp"
+#include "../encoding/tlv-nfd.hpp"
+
+namespace ndn {
+namespace nfd {
+
+enum FaceEventKind
+  {
+    FACE_EVENT_CREATED = 1,
+    FACE_EVENT_DESTROYED = 2
+  };
+
+class FaceEventNotification
+{
+public:
+  class Error : public Tlv::Error
+  {
+  public:
+    Error(const std::string& what) : Tlv::Error(what) { }
+  };
+
+  FaceEventNotification(const FaceEventKind eventKind,
+                        const uint64_t faceId,
+                        const std::string& uri);
+
+  explicit
+  FaceEventNotification(const Block& block);
+
+  uint64_t
+  getFaceId() const
+  {
+    return m_faceId;
+  }
+
+  const std::string&
+  getUri() const
+  {
+    return m_uri;
+  }
+
+  FaceEventKind
+  getEventKind() const
+  {
+    return m_kind;
+  }
+
+  template<bool T>
+  size_t
+  wireEncode(EncodingImpl<T>& buffer) const;
+
+  const Block&
+  wireEncode() const;
+
+  void
+  wireDecode(const Block& wire);
+
+private:
+  FaceEventKind m_kind;
+  uint64_t m_faceId;
+  std::string m_uri;
+
+  mutable Block m_wire;
+};
+
+inline
+FaceEventNotification::FaceEventNotification(const FaceEventKind eventKind,
+                                             const uint64_t faceId,
+                                             const std::string& uri)
+  : m_kind(eventKind)
+  , m_faceId(faceId)
+  , m_uri(uri)
+{
+}
+
+inline
+FaceEventNotification::FaceEventNotification(const Block& block)
+{
+  wireDecode(block);
+}
+
+template<bool T>
+size_t
+FaceEventNotification::wireEncode(EncodingImpl<T>& buffer) const
+{
+  size_t totalLength = 0;
+
+  totalLength += prependByteArrayBlock(buffer,
+                                       tlv::nfd::Uri,
+                                       reinterpret_cast<const uint8_t*>(m_uri.c_str()),
+                                       m_uri.size());
+
+  totalLength += prependNonNegativeIntegerBlock(buffer,
+                                                tlv::nfd::FaceId,
+                                                m_faceId);
+
+  totalLength += prependNonNegativeIntegerBlock(buffer,
+                                                tlv::nfd::FaceEventKind,
+                                                static_cast<uint32_t>(m_kind));
+
+  totalLength += buffer.prependVarNumber(totalLength);
+  totalLength += buffer.prependVarNumber(tlv::nfd::FaceEventNotification);
+
+  return totalLength;
+}
+
+const Block&
+FaceEventNotification::wireEncode() const
+{
+  if (m_wire.hasWire ())
+    return m_wire;
+
+  EncodingEstimator estimator;
+  size_t estimatedSize = wireEncode(estimator);
+
+  EncodingBuffer buffer(estimatedSize, 0);
+  wireEncode(buffer);
+
+  m_wire = buffer.block();
+  return m_wire;
+}
+
+inline void
+FaceEventNotification::wireDecode (const Block &wire)
+{
+  m_wire = wire;
+
+  if (m_wire.type() != tlv::nfd::FaceEventNotification)
+    throw Error("Requested decoding of FaceEventNotification, but Block is of different type");
+
+  m_wire.parse();
+
+  // FaceKind
+  Block::element_const_iterator val = m_wire.elements_begin();
+  if (val == m_wire.elements_end() || val->type() != tlv::nfd::FaceEventKind)
+    throw Error("Missing required Uri block");
+  m_kind = static_cast<FaceEventKind>(readNonNegativeInteger(*val));
+
+  // FaceID
+  ++val;
+  if (val == m_wire.elements_end() || val->type() != tlv::nfd::FaceId)
+    throw Error("Missing required FaceId block");
+  m_faceId = readNonNegativeInteger(*val);
+
+  // URI
+  ++val;
+  if (val == m_wire.elements_end() || val->type() != tlv::nfd::Uri)
+    throw Error("Missing required Uri block");
+  m_uri = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
+}
+
+inline std::ostream&
+operator << (std::ostream& os, const FaceEventNotification& event)
+{
+  os << "FaceEventNotification(";
+
+  os << "Kind: ";
+  switch (event.getEventKind())
+    {
+    case FACE_EVENT_CREATED:
+      os << "created";
+      break;
+    case FACE_EVENT_DESTROYED:
+      os << "destroyed";
+      break;
+    }
+  os << ", ";
+
+  // FaceID
+  os << "FaceID: " << event.getFaceId() << ", ";
+
+  // URI
+  os << "Uri: " << event.getUri();
+
+  os << ")";
+  return os;
+}
+
+} // namespace nfd
+} // namespace ndn
+
+#endif // NDN_MANAGEMENT_NFD_FACE_EVENT_NOTIFICATION_HPP
diff --git a/src/management/nfd-fib-entry.hpp b/src/management/nfd-fib-entry.hpp
index e38dbb7..ea22856 100644
--- a/src/management/nfd-fib-entry.hpp
+++ b/src/management/nfd-fib-entry.hpp
@@ -36,6 +36,7 @@
   {
   }
 
+  explicit
   NextHopRecord(const Block& block)
   {
     wireDecode(block);
@@ -177,7 +178,12 @@
 
   FibEntry()
   {
+  }
 
+  explicit
+  FibEntry(const Block& block)
+  {
+    wireDecode(block);
   }
 
   const Name&
@@ -299,7 +305,7 @@
                   << val->type();
             throw Error(error.str());
           }
-        m_nextHopRecords.push_back(*val);
+        m_nextHopRecords.push_back(NextHopRecord(*val));
       }
   }
 
@@ -314,4 +320,3 @@
 } // namespace ndn
 
 #endif // NDN_MANAGEMENT_NFD_FIB_ENTRY_HPP
-
diff --git a/tests/management/test-nfd-control.cpp b/tests/management/test-nfd-control.cpp
index 2e53512..299620e 100644
--- a/tests/management/test-nfd-control.cpp
+++ b/tests/management/test-nfd-control.cpp
@@ -7,6 +7,7 @@
 #include "management/nfd-control-response.hpp"
 #include "management/nfd-fib-management-options.hpp"
 #include "management/nfd-face-management-options.hpp"
+#include "management/nfd-face-event-notification.hpp"
 
 #include <boost/test/unit_test.hpp>
 #include <boost/test/output_test_stream.hpp>
@@ -39,6 +40,12 @@
   0x6c, 0x6f, 0x2f, 0x77, 0x6f, 0x72, 0x6c, 0x64
 };
 
+const uint8_t TestFaceEventNotification[] = {
+  0xc0, 0x1d, 0xc1, 0x01, 0x01, 0x69, 0x01, 0x64, 0x72, 0x15, 0x74, 0x63,
+  0x70, 0x34, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30,
+  0x2e, 0x31, 0x3a, 0x36, 0x33, 0x36, 0x33
+};
+
 // ControlResponse
 
 BOOST_AUTO_TEST_CASE(ControlResponseEncode)
@@ -139,12 +146,42 @@
   Block blk(TestFaceManagementOptions, sizeof(TestFaceManagementOptions));
   FaceManagementOptions opt;
 
-  BOOST_REQUIRE_NO_THROW(opt.wireDecode (blk));
+  BOOST_REQUIRE_NO_THROW(opt.wireDecode(blk));
 
   BOOST_CHECK_EQUAL(opt.getFaceId(), 10);
   BOOST_CHECK_EQUAL(opt.getUri(), "tcp://1.1.1.1/hello/world");
 }
 
+
+BOOST_AUTO_TEST_CASE(FaceEventNotificationEncodingDecoding)
+{
+  FaceEventKind expectedKind = FACE_EVENT_CREATED;
+  std::string expectedUri("tcp4://127.0.0.1:6363");
+  uint64_t expectedFaceId = 100;
+
+  {
+    FaceEventNotification faceEvent(expectedKind, expectedFaceId, expectedUri);
+    BOOST_REQUIRE_NO_THROW(faceEvent.wireEncode());
+
+    BOOST_REQUIRE_EQUAL_COLLECTIONS(TestFaceEventNotification,
+                                    TestFaceEventNotification + sizeof(TestFaceEventNotification),
+                                    faceEvent.wireEncode().begin(), faceEvent.wireEncode().end());
+
+    std::ostringstream os;
+    os << faceEvent;
+    BOOST_CHECK_EQUAL(os.str(), "FaceEventNotification(Kind: created, FaceID: 100, Uri: tcp4://127.0.0.1:6363)");
+  }
+
+  {
+    Block blk(TestFaceEventNotification, sizeof(TestFaceEventNotification));
+    FaceEventNotification faceEvent(blk);
+
+    BOOST_CHECK_EQUAL(faceEvent.getEventKind(), expectedKind);
+    BOOST_CHECK_EQUAL(faceEvent.getFaceId(), expectedFaceId);
+    BOOST_CHECK_EQUAL(faceEvent.getUri(), expectedUri);
+  }
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace nfd