interest: Add Link and SelectedDelegation fields

Change-Id: I1e4bafe8559ef87135de6cb6f209fc94dfa231b0
Refs: #2587
diff --git a/src/interest.cpp b/src/interest.cpp
index 0ae0852..017711a 100644
--- a/src/interest.cpp
+++ b/src/interest.cpp
@@ -36,6 +36,7 @@
 Interest::Interest()
   : m_scope(-1)
   , m_interestLifetime(time::milliseconds::min())
+  , m_selectedDelegationIndex(INVALID_SELECTED_DELEGATION_INDEX)
 {
 }
 
@@ -43,6 +44,7 @@
   : m_name(name)
   , m_scope(-1)
   , m_interestLifetime(time::milliseconds::min())
+  , m_selectedDelegationIndex(INVALID_SELECTED_DELEGATION_INDEX)
 {
 }
 
@@ -50,6 +52,7 @@
   : m_name(name)
   , m_scope(-1)
   , m_interestLifetime(interestLifetime)
+  , m_selectedDelegationIndex(INVALID_SELECTED_DELEGATION_INDEX)
 {
 }
 
@@ -62,6 +65,7 @@
   , m_selectors(selectors)
   , m_scope(scope)
   , m_interestLifetime(interestLifetime)
+  , m_selectedDelegationIndex(INVALID_SELECTED_DELEGATION_INDEX)
 {
   if (nonce > 0) {
     setNonce(nonce);
@@ -239,9 +243,23 @@
   //                Nonce
   //                Scope?
   //                InterestLifetime?
+  //                Link?
+  //                SelectedDelegation?
 
   // (reverse encoding)
 
+  if (hasLink()) {
+    if (hasSelectedDelegation()) {
+      totalLength += prependNonNegativeIntegerBlock(block,
+                                                    tlv::SelectedDelegation,
+                                                    m_selectedDelegationIndex);
+    }
+    totalLength += prependBlock(block, m_link);
+  }
+  else {
+    BOOST_ASSERT(!hasSelectedDelegation());
+  }
+
   // InterestLifetime
   if (getInterestLifetime() >= time::milliseconds::zero() &&
       getInterestLifetime() != DEFAULT_INTEREST_LIFETIME)
@@ -311,6 +329,8 @@
   //                Nonce
   //                Scope?
   //                InterestLifetime?
+  //                Link?
+  //                SelectedDelegation?
 
   if (m_wire.type() != tlv::Interest)
     throw Error("Unexpected TLV number when decoding Interest");
@@ -349,6 +369,114 @@
     {
       m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
     }
+
+  // Link object
+  val = m_wire.find(tlv::Data);
+  if (val != m_wire.elements_end())
+    {
+      m_link = (*val);
+    }
+
+  // SelectedDelegation
+  val = m_wire.find(tlv::SelectedDelegation);
+  if (val != m_wire.elements_end()) {
+    if (!this->hasLink()) {
+      throw Error("Interest contains selectedDelegation, but no LINK object");
+    }
+    uint64_t selectedDelegation = readNonNegativeInteger(*val);
+    if (selectedDelegation < uint64_t(Link::countDelegationsFromWire(m_link))) {
+      m_selectedDelegationIndex = static_cast<size_t>(selectedDelegation);
+    }
+    else {
+      throw Error("Invalid selected delegation index when decoding Interest");
+    }
+  }
+}
+
+bool
+Interest::hasLink() const
+{
+  if (m_link.hasWire())
+    return true;
+  return false;
+}
+
+Link
+Interest::getLink() const
+{
+  if (hasLink())
+    {
+      return Link(m_link);
+    }
+  throw Error("There is no encapsulated link object");
+}
+
+void
+Interest::setLink(const Block& link)
+{
+  m_link = link;
+  if (!link.hasWire()) {
+    throw Error("The given link does not have a wire format");
+  }
+  m_wire.reset();
+  this->unsetSelectedDelegation();
+}
+
+void
+Interest::unsetLink()
+{
+  m_link.reset();
+  m_wire.reset();
+  this->unsetSelectedDelegation();
+}
+
+bool
+Interest::hasSelectedDelegation() const
+{
+  if (m_selectedDelegationIndex != INVALID_SELECTED_DELEGATION_INDEX)
+    {
+      return true;
+    }
+  return false;
+}
+
+Name
+Interest::getSelectedDelegation() const
+{
+  if (!hasSelectedDelegation()) {
+    throw Error("There is no encapsulated selected delegation");
+  }
+  return std::get<1>(Link::getDelegationFromWire(m_link, m_selectedDelegationIndex));
+}
+
+void
+Interest::setSelectedDelegation(const Name& delegationName)
+{
+  size_t delegationIndex = Link::findDelegationFromWire(m_link, delegationName);
+  if (delegationIndex != INVALID_SELECTED_DELEGATION_INDEX) {
+    m_selectedDelegationIndex = delegationIndex;
+  }
+  else {
+    throw std::invalid_argument("Invalid selected delegation name");
+  }
+  m_wire.reset();
+}
+
+void
+Interest::setSelectedDelegation(size_t delegationIndex)
+{
+  if (delegationIndex >= Link(m_link).getDelegations().size()) {
+    throw Error("Invalid selected delegation index");
+  }
+  m_selectedDelegationIndex = delegationIndex;
+  m_wire.reset();
+}
+
+void
+Interest::unsetSelectedDelegation()
+{
+  m_selectedDelegationIndex = INVALID_SELECTED_DELEGATION_INDEX;
+  m_wire.reset();
 }
 
 std::ostream&
diff --git a/src/interest.hpp b/src/interest.hpp
index 48f34f7..1e064fb 100644
--- a/src/interest.hpp
+++ b/src/interest.hpp
@@ -29,6 +29,7 @@
 #include "util/time.hpp"
 #include "management/nfd-local-control-header.hpp"
 #include "tag-host.hpp"
+#include "link.hpp"
 
 namespace ndn {
 
@@ -130,6 +131,76 @@
   std::string
   toUri() const;
 
+public: // Link and forwarding hint
+
+   /**
+   * @brief Check whether the Interest contains a Link object
+   * @return True if there is a link object, otherwise false
+   */
+  bool
+  hasLink() const;
+
+  /**
+   * @brief Get the link object for this interest
+   * @return The link object if there is one contained in this interest
+   * @throws Interest::Error if there is no link object contained in the interest
+   */
+  Link
+  getLink() const;
+
+  /**
+   * @brief Set the link object for this interest
+   * @param link The link object that will be included in this interest (in wire format)
+   * @post !hasSelectedDelegation()
+   */
+  void
+  setLink(const Block& link);
+
+  /**
+   *@brief Reset the wire format of the given interest and the contained link
+   */
+  void
+  unsetLink();
+
+  /**
+   * @brief Check whether the Interest includes a selected delegation
+   * @return True if there is a selected delegation, otherwise false
+   */
+  bool
+  hasSelectedDelegation() const;
+
+  /**
+   * @brief Get the name of the selected delegation
+   * @return The name of the selected delegation
+   * @throw Error SelectedDelegation is not set.
+   */
+  Name
+  getSelectedDelegation() const;
+
+  /**
+   * @brief Set the selected delegation
+   * @param delegationName The name of the selected delegation
+   * @throw Error Link is not set.
+   * @throw std::invalid_argument @p delegationName does not exist in Link.
+   */
+  void
+  setSelectedDelegation(const Name& delegationName);
+
+  /**
+   * @brief Set the selected delegation
+   * @param delegation The index of the selected delegation
+   * @throw Error Link is not set.
+   * @throw std::out_of_range @p delegationIndex is out of bound in Link.
+   */
+  void
+  setSelectedDelegation(size_t delegationIndex);
+
+   /**
+   * @brief Unset the selected delegation
+   */
+  void
+  unsetSelectedDelegation();
+
 public: // matching
   /** @brief Check if Interest, including selectors, matches the given @p name
    *  @param name The name to be matched. If this is a Data name, it shall contain the
@@ -395,6 +466,8 @@
   int m_scope;
   time::milliseconds m_interestLifetime;
 
+  mutable Block m_link;
+  size_t m_selectedDelegationIndex;
   mutable Block m_wire;
 
   nfd::LocalControlHeader m_localControlHeader;
diff --git a/src/link.cpp b/src/link.cpp
index 07ac0d9..ce05b36 100644
--- a/src/link.cpp
+++ b/src/link.cpp
@@ -179,6 +179,53 @@
   decodeContent();
 }
 
+std::tuple<uint32_t, Name>
+Link::getDelegationFromWire(const Block& block, size_t index)
+{
+  block.parse();
+  const Block& contentBlock = block.get(tlv::Content);
+  contentBlock.parse();
+  const Block& delegationBlock = contentBlock.elements().at(index);
+  delegationBlock.parse();
+  if (delegationBlock.type() != tlv::LinkDelegation) {
+    throw Error("Unexpected TLV-TYPE; expecting LinkDelegation");
+  }
+  return std::make_tuple(
+    static_cast<uint32_t>(
+      readNonNegativeInteger(delegationBlock.get(tlv::LinkPreference))),
+    Name(delegationBlock.get(tlv::Name)));
+}
+
+ssize_t
+Link::findDelegationFromWire(const Block& block, const Name& delegationName)
+{
+  block.parse();
+  const Block& contentBlock = block.get(tlv::Content);
+  contentBlock.parse();
+  size_t counter = 0;
+  for (auto&& delegationBlock : contentBlock.elements()) {
+    delegationBlock.parse();
+    if (delegationBlock.type() != tlv::LinkDelegation) {
+      throw Error("Unexpected TLV-TYPE; expecting LinkDelegation");
+    }
+    Name name(delegationBlock.get(tlv::Name));
+    if (name == delegationName) {
+      return counter;
+    }
+    ++counter;
+  }
+  return INVALID_SELECTED_DELEGATION_INDEX;
+}
+
+ssize_t
+Link::countDelegationsFromWire(const Block& block)
+{
+  block.parse();
+  const Block& contentBlock = block.get(tlv::Content);
+  contentBlock.parse();
+  return contentBlock.elements_size();
+}
+
 bool
 Link::removeDelegationNoEncode(const Name& name)
 {
diff --git a/src/link.hpp b/src/link.hpp
index 3ccb7a3..e4e9f38 100644
--- a/src/link.hpp
+++ b/src/link.hpp
@@ -129,12 +129,34 @@
 
   /**
    * @brief Decode from the wire format
+   * @warning This method does not preserve the relative order between delegations.
+   *     To get a delegation by index, use \p getDelegationFromWire method.
    */
   void
   wireDecode(const Block& wire);
 
+  /** @brief gets the delegation at \p index from \p block
+   *  @param block wire format of a Link object
+   *  @param index 0-based index of a delegation in the Link object
+   *  @return delegation preference and name
+   *  @throw std::out_of_range index is out of range
+   */
+  static std::tuple<uint32_t, Name>
+  getDelegationFromWire(const Block& block, size_t index);
+
+  /** @brief finds index of a delegation with \p delegationName from \p block
+   *  @param block wire format of a Link object
+   *  @return 0-based index of the first delegation with \p delegationName ,
+   *          or -1 if no such delegation exists
+   */
+  static ssize_t
+  findDelegationFromWire(const Block& block, const Name& delegationName);
+
+  static ssize_t
+  countDelegationsFromWire(const Block& block);
+
 protected:
-  /** \brief prepend Link object as a Content block to the encoder
+  /** @brief prepend Link object as a Content block to the encoder
    *
    *  The outermost Content element is not part of Link object structure.
    */
diff --git a/tests/unit-tests/interest.t.cpp b/tests/unit-tests/interest.t.cpp
index be466b0..42be675 100644
--- a/tests/unit-tests/interest.t.cpp
+++ b/tests/unit-tests/interest.t.cpp
@@ -24,6 +24,7 @@
 #include "data.hpp"
 #include "security/signature-sha256-with-rsa.hpp"
 #include "security/digest-sha256.hpp"
+#include "security/key-chain.hpp"
 #include "encoding/buffer-stream.hpp"
 
 #include "boost-test.hpp"
@@ -109,6 +110,392 @@
           0x2,  0x3,  0xe8
 };
 
+const uint8_t InterestWithLink[] = {
+  0x05,  0xfb, // Interest
+      0x07,  0x14, // Name
+          0x08,  0x5, // NameComponent
+              0x6c,  0x6f,  0x63,  0x61,  0x6c,
+          0x08,  0x3, // NameComponent
+              0x6e,  0x64,  0x6e,
+          0x08,  0x6, // NameComponent
+              0x70,  0x72,  0x65,  0x66,  0x69,  0x78,
+      0x0a,  0x4, // Nonce
+          0x1, 0x0, 0x0, 0x00,
+      0x06, 0xda, // Data
+          0x07, 0x14, // Name
+              0x08, 0x05,
+                  0x6c, 0x6f, 0x63, 0x61, 0x6c,
+              0x08, 0x03,
+                  0x6e, 0x64, 0x6e,
+              0x08, 0x06,
+                  0x70, 0x72, 0x65, 0x66, 0x69, 0x78,
+          0x14, 0x07, // MetaInfo
+              0x18, 0x01, // ContentType
+                  0x01,
+              0x19, 0x02, // FreshnessPeriod
+                  0x27, 0x10,
+          0x15, 0x1a, // Content
+              0x1f, 0x0c, // LinkDelegation
+                  0x1e, 0x01, // LinkPreference
+                      0x0a,
+                  0x07, 0x07, // Name
+                      0x08, 0x05,
+                          0x6c, 0x6f, 0x63, 0x61, 0x6c,
+              0x1f, 0x0a, // LinkDelegation
+                  0x1e, 0x01, // LinkPreference
+                      0x14,
+                  0x07, 0x05, // Name
+                      0x08, 0x03,
+                          0x6e, 0x64, 0x6e,
+           0x16, 0x1b, // SignatureInfo
+               0x1b, 0x01, // SignatureType
+                   0x01,
+           0x1c, 0x16, // KeyLocator
+               0x07, 0x14, // Name
+                   0x08, 0x04,
+                       0x74, 0x65, 0x73, 0x74,
+                   0x08, 0x03,
+                       0x6b, 0x65, 0x79,
+                   0x08, 0x07,
+                       0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72,
+           0x17, 0x80, // SignatureValue
+               0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec,
+               0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6,
+               0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38,
+               0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc,
+               0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf,
+               0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9,
+               0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8,
+               0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7,
+               0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3,
+               0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1,
+      0x20, 0x01, // SelectedDelegation
+          0x00
+};
+
+const uint8_t InterestWithLinkMissingContentType[] = {
+  0x05,  0xf8, // Interest
+      0x07,  0x14, // Name
+          0x08,  0x5, // NameComponent
+              0x6c,  0x6f,  0x63,  0x61,  0x6c,
+          0x08,  0x3, // NameComponent
+              0x6e,  0x64,  0x6e,
+          0x08,  0x6, // NameComponent
+              0x70,  0x72,  0x65,  0x66,  0x69,  0x78,
+      0x0a,  0x4, // Nonce
+          0x1, 0x0, 0x0, 0x00,
+      0x06, 0xd7, // Data
+          0x07, 0x14, // Name
+              0x08, 0x05,
+                  0x6c, 0x6f, 0x63, 0x61, 0x6c,
+              0x08, 0x03,
+                  0x6e, 0x64, 0x6e,
+              0x08, 0x06,
+                  0x70, 0x72, 0x65, 0x66, 0x69, 0x78,
+          0x14, 0x04, // MetaInfo
+              0x19, 0x02, // FreshnessPeriod
+                  0x27, 0x10,
+          0x15, 0x1a, // Content
+              0x1f, 0x0c, // LinkDelegation
+                  0x1e, 0x01, // LinkPreference
+                      0x0a,
+                  0x07, 0x07, // Name
+                      0x08, 0x05,
+                          0x6c, 0x6f, 0x63, 0x61, 0x6c,
+              0x1f, 0x0a, // LinkDelegation
+                  0x1e, 0x01, // LinkPreference
+                      0x14,
+                  0x07, 0x05, // Name
+                      0x08, 0x03,
+                          0x6e, 0x64, 0x6e,
+           0x16, 0x1b, // SignatureInfo
+               0x1b, 0x01, // SignatureType
+                   0x01,
+           0x1c, 0x16, // KeyLocator
+               0x07, 0x14, // Name
+                   0x08, 0x04,
+                       0x74, 0x65, 0x73, 0x74,
+                   0x08, 0x03,
+                       0x6b, 0x65, 0x79,
+                   0x08, 0x07,
+                       0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72,
+           0x17, 0x80, // SignatureValue
+               0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec,
+               0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6,
+               0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38,
+               0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc,
+               0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf,
+               0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9,
+               0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8,
+               0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7,
+               0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3,
+               0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1,
+      0x20, 0x01, // SelectedDelegation
+          0x00
+};
+
+const uint8_t InterestWithLinkNoMetaInfo[] = {
+  0x05,  0xf2, // Interest
+      0x07,  0x14, // Name
+          0x08,  0x5, // NameComponent
+              0x6c,  0x6f,  0x63,  0x61,  0x6c,
+          0x08,  0x3, // NameComponent
+              0x6e,  0x64,  0x6e,
+          0x08,  0x6, // NameComponent
+              0x70,  0x72,  0x65,  0x66,  0x69,  0x78,
+      0x0a,  0x4, // Nonce
+          0x1, 0x0, 0x0, 0x00,
+      0x06, 0xd1, // Data
+          0x07, 0x14, // Name
+              0x08, 0x05,
+                  0x6c, 0x6f, 0x63, 0x61, 0x6c,
+              0x08, 0x03,
+                  0x6e, 0x64, 0x6e,
+              0x08, 0x06,
+                  0x70, 0x72, 0x65, 0x66, 0x69, 0x78,
+          0x15, 0x1a, // Content
+              0x1f, 0x0c, // LinkDelegation
+                  0x1e, 0x01, // LinkPreference
+                      0x0a,
+                  0x07, 0x07, // Name
+                      0x08, 0x05,
+                          0x6c, 0x6f, 0x63, 0x61, 0x6c,
+              0x1f, 0x0a, // LinkPreference
+                  0x1e, 0x01, // LinkPreference
+                      0x14,
+                  0x07, 0x05, // Name
+                      0x08, 0x03,
+                          0x6e, 0x64, 0x6e,
+           0x16, 0x1b, // SignatureInfo
+               0x1b, 0x01, // SignatureType
+                   0x01,
+           0x1c, 0x16, // KeyLocator
+               0x07, 0x14, // Name
+                   0x08, 0x04,
+                       0x74, 0x65, 0x73, 0x74,
+                   0x08, 0x03,
+                       0x6b, 0x65, 0x79,
+                   0x08, 0x07,
+                       0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72,
+           0x17, 0x80, // SignatureValue
+               0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec,
+               0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6,
+               0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38,
+               0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc,
+               0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf,
+               0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9,
+               0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8,
+               0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7,
+               0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3,
+               0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1,
+      0x20, 0x01, // SelectedDelegation
+          0x00
+};
+
+const uint8_t InterestWithLinkWrongContentType[] = {
+  0x05,  0xfb, // Interest
+      0x07,  0x14, // Name
+          0x08,  0x5, // NameComponent
+              0x6c,  0x6f,  0x63,  0x61,  0x6c,
+          0x08,  0x3, // NameComponent
+              0x6e,  0x64,  0x6e,
+          0x08,  0x6, // NameComponent
+              0x70,  0x72,  0x65,  0x66,  0x69,  0x78,
+      0x0a,  0x4, // Nonce
+          0x1, 0x0, 0x0, 0x00,
+      0x06, 0xda, // Data
+          0x07, 0x14, // Name
+              0x08, 0x05,
+                  0x6c, 0x6f, 0x63, 0x61, 0x6c,
+              0x08, 0x03,
+                  0x6e, 0x64, 0x6e,
+              0x08, 0x06,
+                  0x70, 0x72, 0x65, 0x66, 0x69, 0x78,
+          0x14, 0x07, // MetaInfo
+              0x18, 0x01, // ContentType
+                  0x00,
+              0x19, 0x02, // FreshnessPeriod
+                  0x27, 0x10,
+          0x15, 0x1a, // Content
+              0x1f, 0x0c, // LinkDelegation
+                  0x1e, 0x01, // LinkPreference
+                      0x0a,
+                  0x07, 0x07, // Name
+                      0x08, 0x05,
+                          0x6c, 0x6f, 0x63, 0x61, 0x6c,
+              0x1f, 0x0a, // LinkDelegation
+                  0x1e, 0x01, // LinkPreference
+                      0x14,
+                  0x07, 0x05, // Name
+                      0x08, 0x03,
+                          0x6e, 0x64, 0x6e,
+           0x16, 0x1b, // SignatureInfo
+               0x1b, 0x01, // SignatureType
+                   0x01,
+           0x1c, 0x16, // KeyLocator
+               0x07, 0x14, // Name
+                   0x08, 0x04,
+                       0x74, 0x65, 0x73, 0x74,
+                   0x08, 0x03,
+                       0x6b, 0x65, 0x79,
+                   0x08, 0x07,
+                       0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72,
+           0x17, 0x80, // SignatureValue
+               0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec,
+               0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6,
+               0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38,
+               0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc,
+               0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf,
+               0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9,
+               0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8,
+               0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7,
+               0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3,
+               0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1,
+      0x20, 0x01, // SelectedDelegation
+          0x00
+};
+
+const uint8_t InterestWithSelectedDelegationButNoLink[] = {
+  0x05,  0x1f, // Interest
+      0x07,  0x14, // Name
+          0x08,  0x5, // NameComponent
+              0x6c,  0x6f,  0x63,  0x61,  0x6c,
+          0x08,  0x3, // NameComponent
+              0x6e,  0x64,  0x6e,
+          0x08,  0x6, // NameComponent
+              0x70,  0x72,  0x65,  0x66,  0x69,  0x78,
+      0x0a,  0x4, // Nonce
+          0x1, 0x0, 0x0, 0x00,
+      0x20, 0x01, // SelectedDelegation
+          0x00
+};
+
+const uint8_t InterestWithLinkNotNonIntegerSelectedDelegation[] = {
+  0x05,  0xfb, // Interest
+      0x07,  0x14, // Name
+          0x08,  0x5, // NameComponent
+              0x6c,  0x6f,  0x63,  0x61,  0x6c,
+          0x08,  0x3, // NameComponent
+              0x6e,  0x64,  0x6e,
+          0x08,  0x6, // NameComponent
+              0x70,  0x72,  0x65,  0x66,  0x69,  0x78,
+      0x0a,  0x4, // Nonce
+          0x1, 0x0, 0x0, 0x00,
+      0x06, 0xda, // Data
+          0x07, 0x14, // Name
+              0x08, 0x05,
+                  0x6c, 0x6f, 0x63, 0x61, 0x6c,
+              0x08, 0x03,
+                  0x6e, 0x64, 0x6e,
+              0x08, 0x06,
+                  0x70, 0x72, 0x65, 0x66, 0x69, 0x78,
+          0x14, 0x07, // MetaInfo
+              0x18, 0x01, // ContentType
+                  0x01,
+              0x19, 0x02, // FreshnessPeriod
+                  0x27, 0x10,
+          0x15, 0x1a, // Content
+              0x1f, 0x0c, // LinkDelegation
+                  0x1e, 0x01, // LinkPreference
+                      0x0a,
+                  0x07, 0x07, // Name
+                      0x08, 0x05,
+                          0x6c, 0x6f, 0x63, 0x61, 0x6c,
+              0x1f, 0x0a, // LinkDelegation
+                  0x1e, 0x01, // LinkPreference
+                      0x14,
+                  0x07, 0x05, // Name
+                      0x08, 0x03,
+                          0x6e, 0x64, 0x6e,
+           0x16, 0x1b, // SignatureInfo
+               0x1b, 0x01, // SignatureType
+                   0x01,
+           0x1c, 0x16, // KeyLocator
+               0x07, 0x14, // Name
+                   0x08, 0x04,
+                       0x74, 0x65, 0x73, 0x74,
+                   0x08, 0x03,
+                       0x6b, 0x65, 0x79,
+                   0x08, 0x07,
+                       0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72,
+           0x17, 0x78, // SignatureValue
+               0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec,
+               0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6,
+               0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38,
+               0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc,
+               0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf,
+               0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9,
+               0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8,
+               0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7,
+               0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3,
+               0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7,
+      0x20, 0x03, // SelectedDelegation
+          0xAA, 0xAA, 0xAA
+};
+
+const uint8_t InterestWithLinkNonDecreasingOrder[] = {
+  0x05,  0xfb, // Interest
+      0x07,  0x14, // Name
+          0x08,  0x5, // NameComponent
+              0x6c,  0x6f,  0x63,  0x61,  0x6c,
+          0x08,  0x3, // NameComponent
+              0x6e,  0x64,  0x6e,
+          0x08,  0x6, // NameComponent
+              0x70,  0x72,  0x65,  0x66,  0x69,  0x78,
+      0x0a,  0x4, // Nonce
+          0x1, 0x0, 0x0, 0x00,
+      0x06, 0xda, // Data
+          0x07, 0x14, // Name
+              0x08, 0x05,
+                  0x6c, 0x6f, 0x63, 0x61, 0x6c,
+              0x08, 0x03,
+                  0x6e, 0x64, 0x6e,
+              0x08, 0x06,
+                  0x70, 0x72, 0x65, 0x66, 0x69, 0x78,
+          0x14, 0x07, // MetaInfo
+              0x18, 0x01, // ContentType
+                  0x01,
+              0x19, 0x02, // FreshnessPeriod
+                  0x27, 0x10,
+          0x15, 0x1a, // Content
+              0x1f, 0x0c, // LinkDelegation
+                  0x1e, 0x01, // LinkPreference
+                      0x14,
+                  0x07, 0x07, // Name
+                      0x08, 0x05,
+                          0x6c, 0x6f, 0x63, 0x61, 0x6c,
+              0x1f, 0x0a, // LinkDelegation
+                  0x1e, 0x01, // LinkPreference
+                      0x0a,
+                  0x07, 0x05, // Name
+                      0x08, 0x03,
+                          0x6e, 0x64, 0x6e,
+           0x16, 0x1b, // SignatureInfo
+               0x1b, 0x01, // SignatureType
+                   0x01,
+           0x1c, 0x16, // KeyLocator
+               0x07, 0x14, // Name
+                   0x08, 0x04,
+                       0x74, 0x65, 0x73, 0x74,
+                   0x08, 0x03,
+                       0x6b, 0x65, 0x79,
+                   0x08, 0x07,
+                       0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72,
+           0x17, 0x80, // SignatureValue
+               0x2f, 0xd6, 0xf1, 0x6e, 0x80, 0x6f, 0x10, 0xbe, 0xb1, 0x6f, 0x3e, 0x31, 0xec,
+               0xe3, 0xb9, 0xea, 0x83, 0x30, 0x40, 0x03, 0xfc, 0xa0, 0x13, 0xd9, 0xb3, 0xc6,
+               0x25, 0x16, 0x2d, 0xa6, 0x58, 0x41, 0x69, 0x62, 0x56, 0xd8, 0xb3, 0x6a, 0x38,
+               0x76, 0x56, 0xea, 0x61, 0xb2, 0x32, 0x70, 0x1c, 0xb6, 0x4d, 0x10, 0x1d, 0xdc,
+               0x92, 0x8e, 0x52, 0xa5, 0x8a, 0x1d, 0xd9, 0x96, 0x5e, 0xc0, 0x62, 0x0b, 0xcf,
+               0x3a, 0x9d, 0x7f, 0xca, 0xbe, 0xa1, 0x41, 0x71, 0x85, 0x7a, 0x8b, 0x5d, 0xa9,
+               0x64, 0xd6, 0x66, 0xb4, 0xe9, 0x8d, 0x0c, 0x28, 0x43, 0xee, 0xa6, 0x64, 0xe8,
+               0x55, 0xf6, 0x1c, 0x19, 0x0b, 0xef, 0x99, 0x25, 0x1e, 0xdc, 0x78, 0xb3, 0xa7,
+               0xaa, 0x0d, 0x14, 0x58, 0x30, 0xe5, 0x37, 0x6a, 0x6d, 0xdb, 0x56, 0xac, 0xa3,
+               0xfc, 0x90, 0x7a, 0xb8, 0x66, 0x9c, 0x0e, 0xf6, 0xb7, 0x64, 0xd1,
+      0x20, 0x01, // SelectedDelegation
+          0x01
+};
+
 const uint8_t InterestWithLocalControlHeader[] = {
   0x50, 0x25, 0x51, 0x01, 0x0a,
   0x05, 0x20, 0x07, 0x14, 0x08, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x08, 0x03, 0x6e, 0x64,
@@ -130,6 +517,8 @@
   //                Nonce
   //                Scope?
   //                InterestLifetime?
+  //                Link?
+  //                SelectedDelegation?
 
   Interest a;
   Interest b;
@@ -189,6 +578,32 @@
   b.setInterestLifetime(time::seconds(10));
   BOOST_CHECK_EQUAL(a == b, true);
   BOOST_CHECK_EQUAL(a != b, false);
+
+  // Link object
+  Link link("test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}});
+  KeyChain keyChain;
+  keyChain.sign(link);
+  Block wire = link.wireEncode();
+
+  a.setLink(wire);
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setLink(wire);
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
+
+  // Selected Delegation
+  BOOST_CHECK_EQUAL(a.hasSelectedDelegation(), false);
+  BOOST_CHECK_EQUAL(b.hasSelectedDelegation(), false);
+
+  a.setSelectedDelegation(Name("test2"));
+  BOOST_CHECK_EQUAL(a == b, false);
+  BOOST_CHECK_EQUAL(a != b, true);
+
+  b.setSelectedDelegation(Name("test2"));
+  BOOST_CHECK_EQUAL(a == b, true);
+  BOOST_CHECK_EQUAL(a != b, false);
 }
 
 BOOST_AUTO_TEST_CASE(SelectorsEqualityChecks)
@@ -265,6 +680,210 @@
   BOOST_CHECK_EQUAL(a != b, false);
 }
 
+BOOST_AUTO_TEST_CASE(LinkObject)
+{
+  Link link1("test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}});
+  KeyChain keyChain;
+  keyChain.sign(link1);
+  Block wire = link1.wireEncode();
+
+  Interest a;
+  BOOST_REQUIRE_NO_THROW(a.setLink(wire));
+
+  BOOST_REQUIRE_NO_THROW(a.getLink());
+
+  Link link2 = a.getLink();
+  Name name = link2.getName();
+  BOOST_CHECK_EQUAL(Name("test"), name);
+  BOOST_CHECK_EQUAL(a.hasLink(), true);
+  Link::DelegationSet delegations;
+  delegations = link2.getDelegations();
+
+  auto i = delegations.begin();
+  BOOST_CHECK_EQUAL(std::get<0>(*i), 10);
+  BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test1"));
+  ++i;
+  BOOST_CHECK_EQUAL(std::get<0>(*i), 20);
+  BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test2"));
+  ++i;
+  BOOST_CHECK_EQUAL(std::get<0>(*i), 100);
+  BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test3"));
+
+  a.unsetLink();
+  BOOST_CHECK_EQUAL(a.hasLink(), false);
+}
+
+BOOST_AUTO_TEST_CASE(SelectedDelegationChecks)
+{
+  Link link("test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}});
+  KeyChain keyChain;
+  keyChain.sign(link);
+  Block wire = link.wireEncode();
+
+  Interest a;
+  a.setLink(wire);
+  BOOST_CHECK_EQUAL(a.hasSelectedDelegation(), false);
+
+  BOOST_REQUIRE_NO_THROW(a.setSelectedDelegation(Name("test2")));
+  BOOST_CHECK_EQUAL(a.getSelectedDelegation(), Name("test2"));
+
+  BOOST_REQUIRE_NO_THROW(a.setSelectedDelegation(uint32_t(2)));
+  BOOST_CHECK_EQUAL(a.getSelectedDelegation(), Name("test3"));
+
+  a.unsetSelectedDelegation();
+  BOOST_CHECK_EQUAL(a.hasSelectedDelegation(), false);
+}
+
+BOOST_AUTO_TEST_CASE(EncodeDecodeWithLink)
+{
+  Link link1("test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}});
+  KeyChain keyChain;
+  keyChain.sign(link1);
+  Block wire = link1.wireEncode();
+
+  Interest a;
+  a.setName("/Test/Encode/Decode/With/Link");
+  a.setChildSelector(1);
+  a.setNonce(100);
+  a.setScope(1);
+  a.setInterestLifetime(time::seconds(10));
+  a.setLink(wire);
+
+  Block interestBlock = a.wireEncode();
+  Interest b(interestBlock);
+
+  BOOST_CHECK_EQUAL(a == b, true);
+
+  Link link2 = b.getLink();
+  Link::DelegationSet delegations;
+  delegations = link2.getDelegations();
+
+  auto i = delegations.begin();
+  BOOST_CHECK_EQUAL(std::get<0>(*i), 10);
+  BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test1"));
+  ++i;
+  BOOST_CHECK_EQUAL(std::get<0>(*i), 20);
+  BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test2"));
+  ++i;
+  BOOST_CHECK_EQUAL(std::get<0>(*i), 100);
+  BOOST_CHECK_EQUAL(std::get<1>(*i), Name("test3"));
+
+}
+
+BOOST_AUTO_TEST_CASE(DecodeInterestWithLink)
+{
+  Block interestBlock(InterestWithLink, sizeof(InterestWithLink));
+
+  ndn::Interest i;
+  BOOST_REQUIRE_NO_THROW(i.wireDecode(interestBlock));
+  Link link = i.getLink();
+  BOOST_CHECK_EQUAL(link.getName(), Name("/local/ndn/prefix"));
+  Link::DelegationSet delegations = link.getDelegations();
+
+  auto it = delegations.begin();
+  BOOST_CHECK_EQUAL(std::get<0>(*it), 10);
+  BOOST_CHECK_EQUAL(std::get<1>(*it), Name("local"));
+  ++it;
+  BOOST_CHECK_EQUAL(std::get<0>(*it), 20);
+  BOOST_CHECK_EQUAL(std::get<1>(*it), Name("ndn"));
+
+  BOOST_REQUIRE_NO_THROW(i.getSelectedDelegation());
+  BOOST_CHECK_EQUAL(i.getSelectedDelegation(), Name("local"));
+}
+
+BOOST_AUTO_TEST_CASE(DecodeInterestWithLinkNonDecreasingOrder)
+{
+  Block interestBlock(InterestWithLinkNonDecreasingOrder,
+                      sizeof(InterestWithLinkNonDecreasingOrder));
+
+  ndn::Interest i;
+  BOOST_REQUIRE_NO_THROW(i.wireDecode(interestBlock));
+  BOOST_REQUIRE_NO_THROW(i.getSelectedDelegation());
+  BOOST_CHECK_EQUAL(i.getSelectedDelegation(), Name("ndn"));
+}
+
+BOOST_AUTO_TEST_CASE(LinkObjectMissingContentType)
+{
+  Block interestBlock(InterestWithLinkMissingContentType,
+                      sizeof(InterestWithLinkMissingContentType));
+
+  ndn::Interest i;
+  BOOST_REQUIRE_NO_THROW(i.wireDecode(interestBlock));
+  BOOST_REQUIRE_THROW(i.getLink(), Link::Error);
+}
+
+BOOST_AUTO_TEST_CASE(LinkObjectNoMetaInfo)
+{
+  Block interestBlock(InterestWithLinkNoMetaInfo,
+                      sizeof(InterestWithLinkNoMetaInfo));
+
+  ndn::Interest i;
+  BOOST_REQUIRE_NO_THROW(i.wireDecode(interestBlock));
+  BOOST_REQUIRE_THROW(i.getLink(), Block::Error);
+}
+
+BOOST_AUTO_TEST_CASE(LinkObjectWrongContentType)
+{
+  Block interestBlock(InterestWithLinkWrongContentType,
+                      sizeof(InterestWithLinkWrongContentType));
+
+  ndn::Interest i;
+  BOOST_REQUIRE_NO_THROW(i.wireDecode(interestBlock));
+  BOOST_REQUIRE_THROW(i.getLink(), Link::Error);
+}
+
+BOOST_AUTO_TEST_CASE(InterestContainingSelectedDelegationButNoLink)
+{
+  Block interestBlock(InterestWithSelectedDelegationButNoLink,
+                      sizeof(InterestWithSelectedDelegationButNoLink));
+
+  ndn::Interest i;
+  BOOST_REQUIRE_THROW(i.wireDecode(interestBlock), Interest::Error);
+}
+
+BOOST_AUTO_TEST_CASE(SelectedDelegationIsNotNonNegativeInteger)
+{
+  Block interestBlock(InterestWithLinkNotNonIntegerSelectedDelegation,
+                      sizeof(InterestWithLinkNotNonIntegerSelectedDelegation));
+
+  ndn::Interest i;
+  BOOST_REQUIRE_THROW(i.wireDecode(interestBlock), tlv::Error);
+}
+
+BOOST_AUTO_TEST_CASE(SelectedDelegationEqualToDelegationCount)
+{
+  Link link1("test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}});
+  KeyChain keyChain;
+  keyChain.sign(link1);
+  Block wire = link1.wireEncode();
+
+  Interest a;
+  a.setName("/Test/Encode/Decode/With/Link");
+  a.setChildSelector(1);
+  a.setNonce(100);
+  a.setScope(1);
+  a.setInterestLifetime(time::seconds(10));
+  a.setLink(wire);
+  BOOST_REQUIRE_THROW(a.setSelectedDelegation(3), Interest::Error);
+}
+
+BOOST_AUTO_TEST_CASE(SelectedDelegationGreaterThanDelegationCount)
+{
+  Link link1("test", {{10, "/test1"}, {20, "/test2"}, {100, "/test3"}});
+  KeyChain keyChain;
+  keyChain.sign(link1);
+  Block wire = link1.wireEncode();
+
+  Interest a;
+  a.setName("/Test/Encode/Decode/With/Link");
+  a.setChildSelector(1);
+  a.setNonce(100);
+  a.setScope(1);
+  a.setInterestLifetime(time::seconds(10));
+  a.setLink(wire);
+  BOOST_REQUIRE_THROW(a.setSelectedDelegation(4), Interest::Error);
+}
+
 BOOST_AUTO_TEST_CASE(Decode)
 {
   Block interestBlock(Interest1, sizeof(Interest1));
diff --git a/tests/unit-tests/link.t.cpp b/tests/unit-tests/link.t.cpp
index d771b7b..f06a7dd 100644
--- a/tests/unit-tests/link.t.cpp
+++ b/tests/unit-tests/link.t.cpp
@@ -373,6 +373,12 @@
   }
 }
 
+BOOST_AUTO_TEST_CASE(CountDelegationFromWire)
+{
+  Block linkBlock(LinkTest, sizeof(LinkTest));
+  BOOST_CHECK_EQUAL(Link::countDelegationsFromWire(linkBlock), 2);
+}
+
 BOOST_AUTO_TEST_CASE(IncorrectContentType)
 {
   Block linkBlock(IncorrectContentTypeLink, sizeof(IncorrectContentTypeLink));