face: LocalControlHeader attributes

refs #1264

Change-Id: Iab8b875ea8102103390d2da37ca3c08ef58a3d55
diff --git a/daemon/face/face.cpp b/daemon/face/face.cpp
index b32b57a..76ec85b 100644
--- a/daemon/face/face.cpp
+++ b/daemon/face/face.cpp
@@ -5,11 +5,15 @@
  */
 
 #include "face.hpp"
+#include "core/logger.hpp"
 
 namespace nfd {
 
+NFD_LOG_INIT("Face");
+
 Face::Face()
   : m_id(INVALID_FACEID)
+  , m_localControlHeaderFeatures(LOCAL_CONTROL_HEADER_FEATURE_MAX)
 {
 }
 
@@ -60,12 +64,20 @@
   return false;
 }
 
-bool
-Face::isLocalControlHeaderEnabled() const
+void
+Face::setLocalControlHeaderFeature(LocalControlHeaderFeature feature, bool enabled)
 {
-  // TODO add local control header functionality
-  return false;
-}
+  BOOST_ASSERT(feature > LOCAL_CONTROL_HEADER_FEATURE_ANY &&
+               feature < m_localControlHeaderFeatures.size());
+  m_localControlHeaderFeatures[feature] = enabled;
+  NFD_LOG_DEBUG("face" << this->getId() << " setLocalControlHeaderFeature " <<
+                (enabled ? "enable" : "disable") << " feature " << feature);
 
+  BOOST_STATIC_ASSERT(LOCAL_CONTROL_HEADER_FEATURE_ANY == 0);
+  m_localControlHeaderFeatures[LOCAL_CONTROL_HEADER_FEATURE_ANY] =
+    std::find(m_localControlHeaderFeatures.begin() + 1,
+              m_localControlHeaderFeatures.end(), true) !=
+              m_localControlHeaderFeatures.end();
+}
 
 } //namespace nfd
diff --git a/daemon/face/face.hpp b/daemon/face/face.hpp
index 68b8073..d4e4578 100644
--- a/daemon/face/face.hpp
+++ b/daemon/face/face.hpp
@@ -4,8 +4,8 @@
  * See COPYING for copyright and distribution information.
  */
 
-#ifndef NFD_FACE_FACE_H
-#define NFD_FACE_FACE_H
+#ifndef NFD_FACE_FACE_HPP
+#define NFD_FACE_FACE_HPP
 
 #include "common.hpp"
 #include "core/event-emitter.hpp"
@@ -21,6 +21,22 @@
 
 const std::size_t MAX_NDN_PACKET_SIZE = 8800;
 
+
+/* \brief indicates a feature in LocalControlHeader
+ */
+enum LocalControlHeaderFeature
+{
+  /// any feature
+  LOCAL_CONTROL_HEADER_FEATURE_ANY,
+  /// in-faceid
+  LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID,
+  /// out-faceid
+  LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID,
+  /// upper bound of enum
+  LOCAL_CONTROL_HEADER_FEATURE_MAX
+};
+
+
 /** \brief represents a face
  */
 class Face : noncopyable, public enable_shared_from_this<Face>
@@ -35,26 +51,26 @@
   };
 
   Face();
-  
+
   virtual
   ~Face();
-  
+
   FaceId
   getId() const;
 
   /// fires when an Interest is received
   EventEmitter<Interest> onReceiveInterest;
-  
+
   /// fires when a Data is received
   EventEmitter<Data> onReceiveData;
 
   /// fires when face disconnects or fails to perform properly
   EventEmitter<std::string/*reason*/> onFail;
-  
+
   /// send an Interest
   virtual void
   sendInterest(const Interest& interest) = 0;
-  
+
   /// send a Data
   virtual void
   sendData(const Data& data) = 0;
@@ -67,21 +83,21 @@
    */
   virtual void
   close() = 0;
-  
+
   /** \brief Get whether underlying communication is up
    *
    *  In this base class this property is always true.
    */
   virtual bool
   isUp() const;
-  
+
   /** \brief Set the description
    *
    *  This is typically invoked by mgmt on set description command
    */
   virtual void
   setDescription(const std::string& description);
-  
+
   /// Get the description
   virtual const std::string&
   getDescription() const;
@@ -92,17 +108,30 @@
    */
   virtual bool
   isLocal() const;
-  
+
   /** \brief Get whether packets sent this Face may reach multiple peers
    *
    *  In this base class this property is always false.
    */
   virtual bool
   isMultiAccess() const;
-  
-  /// Get whether the face has opted in for local control header
-  virtual bool
-  isLocalControlHeaderEnabled() const;
+
+  /** \brief get whether a LocalControlHeader feature is enabled
+   *
+   *  \param feature The feature. Cannot be LOCAL_CONTROL_HEADER_FEATURE_MAX
+   *  LOCAL_CONTROL_HEADER_FEATURE_ANY returns true if any feature is enabled.
+   */
+  bool
+  isLocalControlHeaderEnabled(LocalControlHeaderFeature feature =
+                              LOCAL_CONTROL_HEADER_FEATURE_ANY) const;
+
+  /** \brief enable or disable a LocalControlHeader feature
+   *
+   *  \param feature The feature. Cannot be LOCAL_CONTROL_HEADER_FEATURE_ANY
+   *                                     or LOCAL_CONTROL_HEADER_FEATURE_MAX
+   */
+  void
+  setLocalControlHeaderFeature(LocalControlHeaderFeature feature, bool enabled);
 
 private:
   void
@@ -111,11 +140,19 @@
 private:
   FaceId m_id;
   std::string m_description;
-  
+  std::vector<bool> m_localControlHeaderFeatures;
+
   // allow setting FaceId
   friend class Forwarder;
 };
 
+inline bool
+Face::isLocalControlHeaderEnabled(LocalControlHeaderFeature feature) const
+{
+  BOOST_ASSERT(feature < m_localControlHeaderFeatures.size());
+  return m_localControlHeaderFeatures[feature];
+}
+
 } // namespace nfd
 
-#endif // NFD_FACE_FACE_H
+#endif // NFD_FACE_FACE_HPP
diff --git a/tests/face/face.cpp b/tests/face/face.cpp
index 5245f51..07e3fb4 100644
--- a/tests/face/face.cpp
+++ b/tests/face/face.cpp
@@ -20,6 +20,25 @@
   BOOST_CHECK_EQUAL(face.getDescription(), "3pFsKrvWr");
 }
 
+BOOST_AUTO_TEST_CASE(LocalControlHeaderEnabled)
+{
+  DummyFace face;
+  
+  BOOST_CHECK_EQUAL(face.isLocalControlHeaderEnabled(), false);
+  
+  face.setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID, true);
+  BOOST_CHECK_EQUAL(face.isLocalControlHeaderEnabled(), true);
+  BOOST_CHECK_EQUAL(face.isLocalControlHeaderEnabled(
+                         LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID), true);
+  BOOST_CHECK_EQUAL(face.isLocalControlHeaderEnabled(
+                         LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID), false);
+  
+  face.setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID, false);
+  BOOST_CHECK_EQUAL(face.isLocalControlHeaderEnabled(), false);
+  BOOST_CHECK_EQUAL(face.isLocalControlHeaderEnabled(
+                         LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID), false);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace nfd