lp: Packet and Fields
refs #2879
Change-Id: Ie450eb58d1176179efed8d1706d30ea4978b7b02
diff --git a/src/lp/detail/field-decl.hpp b/src/lp/detail/field-decl.hpp
new file mode 100644
index 0000000..e6fd4aa
--- /dev/null
+++ b/src/lp/detail/field-decl.hpp
@@ -0,0 +1,150 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_LP_DETAIL_FIELD_DECL_HPP
+#define NDN_CXX_LP_DETAIL_FIELD_DECL_HPP
+
+#include "../../common.hpp"
+
+#include "../field.hpp"
+#include "../sequence.hpp"
+#include "../cache-policy.hpp"
+#include "../nack.hpp"
+#include "../tlv.hpp"
+
+#include <boost/concept/requires.hpp>
+
+namespace ndn {
+namespace lp {
+namespace detail {
+
+template<typename TlvType, typename T>
+struct DecodeHelper
+{
+ static
+ BOOST_CONCEPT_REQUIRES(((WireDecodable<T>)), (T))
+ decode(const Block& wire)
+ {
+ if (wire.type() != TlvType::value) {
+ throw ndn::tlv::Error("Unexpected TLV type " + std::to_string(wire.type()));
+ }
+
+ T type;
+ type.wireDecode(wire);
+ return type;
+ }
+};
+
+template<typename TlvType>
+struct DecodeHelper<TlvType, uint64_t>
+{
+ static uint64_t
+ decode(const Block& wire)
+ {
+ if (wire.type() != TlvType::value) {
+ throw ndn::tlv::Error("Unexpected TLV type " + std::to_string(wire.type()));
+ }
+
+ return readNonNegativeInteger(wire);
+ }
+};
+
+template<typename TlvType>
+struct DecodeHelper<TlvType, std::pair<Buffer::const_iterator, Buffer::const_iterator>>
+{
+ static std::pair<Buffer::const_iterator, Buffer::const_iterator>
+ decode(const Block& wire)
+ {
+ if (wire.type() != TlvType::value) {
+ throw ndn::tlv::Error("Unexpected TLV type " + std::to_string(wire.type()));
+ }
+
+ if (wire.value_size() == 0) {
+ throw ndn::tlv::Error(std::to_string(wire.type()) + " must not be empty");
+ }
+
+ return std::make_pair(wire.value_begin(), wire.value_end());
+ }
+};
+
+template<typename encoding::Tag TAG, typename TlvType, typename T>
+struct EncodeHelper
+{
+ static
+ BOOST_CONCEPT_REQUIRES(((WireEncodable<T>)), (size_t))
+ encode(EncodingImpl<TAG>& encoder, const T& value)
+ {
+ return value.wireEncode(encoder);
+ }
+};
+
+template<typename encoding::Tag TAG, typename TlvType>
+struct EncodeHelper<TAG, TlvType, uint64_t>
+{
+ static size_t
+ encode(EncodingImpl<TAG>& encoder, const uint64_t value)
+ {
+ return prependNonNegativeIntegerBlock(encoder, TlvType::value, value);
+ }
+};
+
+template<typename encoding::Tag TAG, typename TlvType>
+struct EncodeHelper<TAG, TlvType, std::pair<Buffer::const_iterator, Buffer::const_iterator>>
+{
+ static size_t
+ encode(EncodingImpl<TAG>& encoder, const std::pair<Buffer::const_iterator, Buffer::const_iterator>& value)
+ {
+ size_t length = 0;
+ length += encoder.prependRange(value.first, value.second);
+ length += encoder.prependVarNumber(length);
+ length += encoder.prependVarNumber(TlvType::value);
+ return length;
+ }
+};
+
+template<typename LOCATION, typename VALUE, uint64_t TYPE, bool REPEATABLE = false>
+class FieldDecl
+{
+public:
+ typedef LOCATION FieldLocation;
+ typedef VALUE ValueType;
+ typedef std::integral_constant<uint64_t, TYPE> TlvType;
+ typedef std::integral_constant<bool, REPEATABLE> IsRepeatable;
+
+ static ValueType
+ decode(const Block& wire)
+ {
+ return DecodeHelper<TlvType, ValueType>::decode(wire);
+ }
+
+ template<typename encoding::Tag TAG, typename T>
+ static size_t
+ encode(EncodingImpl<TAG>& encoder, const T& value)
+ {
+ return EncodeHelper<TAG, TlvType, T>::encode(encoder, value);
+ }
+};
+
+} // namespace detail
+} // namespace lp
+} // namesapce ndn
+
+#endif // NDN_CXX_LP_DETAIL_FIELD_DECL_HPP
\ No newline at end of file
diff --git a/src/lp/detail/field-info.cpp b/src/lp/detail/field-info.cpp
new file mode 100644
index 0000000..fadd858
--- /dev/null
+++ b/src/lp/detail/field-info.cpp
@@ -0,0 +1,74 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "field-info.hpp"
+
+#include <boost/mpl/for_each.hpp>
+#include <boost/bind.hpp>
+
+namespace ndn {
+namespace lp {
+namespace detail {
+
+struct ExtractFieldInfo
+{
+ typedef void result_type;
+
+ template<typename T>
+ void
+ operator()(FieldInfo* info, T)
+ {
+ if (T::TlvType::value != info->tlvType) {
+ return;
+ }
+ info->isRecognized = true;
+ info->canIgnore = false;
+ info->isRepeatable = T::IsRepeatable::value;
+ info->locationSortOrder = getLocationSortOrder<typename T::FieldLocation>();
+ }
+};
+
+FieldInfo::FieldInfo()
+ : tlvType(0)
+ , isRecognized(false)
+ , canIgnore(false)
+ , isRepeatable(false)
+ , locationSortOrder(getLocationSortOrder<field_location_tags::Header>())
+{
+}
+
+FieldInfo::FieldInfo(uint64_t tlv)
+ : tlvType(tlv)
+ , isRecognized(false)
+ , canIgnore(false)
+ , isRepeatable(false)
+ , locationSortOrder(getLocationSortOrder<field_location_tags::Header>())
+{
+ boost::mpl::for_each<FieldSet>(boost::bind(ExtractFieldInfo(), this, _1));
+ if (!isRecognized) {
+ canIgnore = tlv::HEADER3_MIN <= tlvType && tlvType <= tlv::HEADER3_MAX &&
+ (tlvType & 0x01) == 0x01;
+ }
+}
+
+} // namespace detail
+} // namespace lp
+} // namespace ndn
\ No newline at end of file
diff --git a/src/lp/detail/field-info.hpp b/src/lp/detail/field-info.hpp
new file mode 100644
index 0000000..2ee0e10
--- /dev/null
+++ b/src/lp/detail/field-info.hpp
@@ -0,0 +1,97 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_LP_DETAIL_FIELD_INFO_HPP
+#define NDN_CXX_LP_DETAIL_FIELD_INFO_HPP
+
+#include "../../common.hpp"
+
+#include "../fields.hpp"
+
+namespace ndn {
+namespace lp {
+namespace detail {
+
+class FieldInfo
+{
+public:
+ FieldInfo();
+
+ explicit
+ FieldInfo(uint64_t tlv);
+
+public:
+ /**
+ * \brief TLV-TYPE of the field; 0 if field does not exist
+ */
+ uint64_t tlvType;
+
+ /**
+ * \brief is this field known
+ */
+ bool isRecognized;
+
+ /**
+ * \brief can this unknown field be ignored
+ */
+ bool canIgnore;
+
+ /**
+ * \brief is the field repeatable
+ */
+ bool isRepeatable;
+
+ /**
+ * \brief sort order of field_location_tag
+ */
+ int locationSortOrder;
+};
+
+template<typename TAG>
+inline int
+getLocationSortOrder();
+
+template<>
+inline int
+getLocationSortOrder<field_location_tags::Header>()
+{
+ return 1;
+}
+
+template<>
+inline int
+getLocationSortOrder<field_location_tags::Fragment>()
+{
+ return 2;
+}
+
+inline bool
+compareFieldSortOrder(const FieldInfo& first, const FieldInfo& second)
+{
+ return (first.locationSortOrder < second.locationSortOrder) ||
+ (first.locationSortOrder == second.locationSortOrder && first.tlvType < second.tlvType);
+}
+
+} // namespace detail
+} // namespace lp
+} // namespace ndn
+
+#endif // NDN_CXX_LP_DETAIL_FIELD_INFO_HPP
\ No newline at end of file
diff --git a/src/lp/field.hpp b/src/lp/field.hpp
new file mode 100644
index 0000000..199fb16
--- /dev/null
+++ b/src/lp/field.hpp
@@ -0,0 +1,82 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_LP_FIELD_HPP
+#define NDN_CXX_LP_FIELD_HPP
+
+#include "../common.hpp"
+#include "../encoding/encoding-buffer.hpp"
+
+#include <boost/type_traits.hpp>
+
+namespace ndn {
+namespace lp {
+
+/**
+ * \brief indicates where a field may occur
+ */
+namespace field_location_tags {
+
+class Base
+{
+};
+
+/**
+ * \brief a header field
+ */
+class Header : public Base
+{
+};
+
+/**
+ * \brief the Fragment field
+ */
+class Fragment : public Base
+{
+};
+
+} // namespace field_location_tags
+
+/**
+ * \brief concept check for fields
+ */
+template<class X>
+struct Field
+{
+ BOOST_CONCEPT_ASSERT((boost::is_base_of<field_location_tags::Base, typename X::FieldLocation>));
+ BOOST_CONCEPT_ASSERT((boost::DefaultConstructible<typename X::ValueType>));
+ BOOST_CONCEPT_ASSERT((boost::CopyConstructible<typename X::ValueType>));
+ BOOST_CONCEPT_ASSERT((boost::is_same<typename X::TlvType::value_type, uint64_t>));
+ BOOST_CONCEPT_ASSERT((boost::is_same<typename X::IsRepeatable::value_type, bool>));
+ BOOST_CONCEPT_USAGE(Field)
+ {
+ Block wire;
+ X j;
+ typename X::ValueType decoded = j.decode(wire);
+ EncodingBuffer enc;
+ j.encode(enc, decoded);
+ }
+};
+
+} // namespace lp
+} // namespace ndn
+
+#endif // NDN_CXX_LP_FIELD_HPP
\ No newline at end of file
diff --git a/src/lp/fields.hpp b/src/lp/fields.hpp
new file mode 100644
index 0000000..ad656be
--- /dev/null
+++ b/src/lp/fields.hpp
@@ -0,0 +1,97 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_LP_FIELDS_HPP
+#define NDN_CXX_LP_FIELDS_HPP
+
+#include "../common.hpp"
+
+#include "tlv.hpp"
+#include "detail/field-decl.hpp"
+#include "field.hpp"
+
+#include <boost/mpl/set.hpp>
+
+namespace ndn {
+namespace lp {
+
+typedef detail::FieldDecl<field_location_tags::Header,
+ Sequence,
+ tlv::Sequence> SequenceField;
+BOOST_CONCEPT_ASSERT((Field<SequenceField>));
+
+typedef detail::FieldDecl<field_location_tags::Header,
+ uint64_t,
+ tlv::FragIndex> FragIndexField;
+BOOST_CONCEPT_ASSERT((Field<FragIndexField>));
+
+typedef detail::FieldDecl<field_location_tags::Header,
+ uint64_t,
+ tlv::FragCount> FragCountField;
+BOOST_CONCEPT_ASSERT((Field<FragCountField>));
+
+typedef detail::FieldDecl<field_location_tags::Header,
+ NackHeader,
+ tlv::Nack> NackField;
+BOOST_CONCEPT_ASSERT((Field<NackField>));
+
+typedef detail::FieldDecl<field_location_tags::Header,
+ uint64_t,
+ tlv::NextHopFaceId> NextHopFaceIdField;
+BOOST_CONCEPT_ASSERT((Field<NextHopFaceIdField>));
+
+typedef detail::FieldDecl<field_location_tags::Header,
+ CachePolicy,
+ tlv::CachePolicy> CachePolicyField;
+BOOST_CONCEPT_ASSERT((Field<CachePolicyField>));
+
+typedef detail::FieldDecl<field_location_tags::Header,
+ uint64_t,
+ tlv::IncomingFaceId> IncomingFaceIdField;
+BOOST_CONCEPT_ASSERT((Field<IncomingFaceIdField>));
+
+/**
+ * The value of the wire encoded field is the data between the provided iterators. During
+ * encoding, the data is copied from the Buffer into the wire buffer.
+ */
+typedef detail::FieldDecl<field_location_tags::Fragment,
+ std::pair<Buffer::const_iterator, Buffer::const_iterator>,
+ tlv::Fragment> FragmentField;
+BOOST_CONCEPT_ASSERT((Field<FragmentField>));
+
+/**
+ * \brief set of all field declarations
+ */
+typedef boost::mpl::set<
+ FragmentField,
+ SequenceField,
+ FragIndexField,
+ FragCountField,
+ NackField,
+ NextHopFaceIdField,
+ CachePolicyField,
+ IncomingFaceIdField
+ > FieldSet;
+
+} // namespace lp
+} // namespace ndn
+
+#endif // NDN_CXX_LP_FIELDS_HPP
\ No newline at end of file
diff --git a/src/lp/packet.cpp b/src/lp/packet.cpp
new file mode 100644
index 0000000..20de690
--- /dev/null
+++ b/src/lp/packet.cpp
@@ -0,0 +1,129 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "packet.hpp"
+#include "detail/field-info.hpp"
+
+#include <boost/range/adaptor/reversed.hpp>
+
+namespace ndn {
+namespace lp {
+
+Packet::Packet()
+ : m_wire(Block(tlv::LpPacket))
+{
+}
+
+Packet::Packet(const Block& wire)
+{
+ wireDecode(wire);
+}
+
+template<encoding::Tag TAG>
+size_t
+Packet::wireEncode(EncodingImpl<TAG>& encoder) const
+{
+ if (m_wire.hasWire()) {
+ return m_wire.size();
+ }
+
+ size_t length = 0;
+
+ for (const Block& element : boost::adaptors::reverse(m_wire.elements())) {
+ length += encoder.prependBlock(element);
+ }
+
+ length += encoder.prependVarNumber(length);
+ length += encoder.prependVarNumber(tlv::LpPacket);
+
+ return length;
+}
+
+template size_t
+Packet::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& encoder) const;
+
+template size_t
+Packet::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& encoder) const;
+
+const Block&
+Packet::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;
+}
+
+void
+Packet::wireDecode(const Block& wire)
+{
+ if (wire.type() == ndn::tlv::Interest || wire.type() == ndn::tlv::Data) {
+ m_wire = Block(tlv::LpPacket);
+ add<FragmentField>(make_pair(wire.begin(), wire.end()));
+ return;
+ }
+
+ wire.parse();
+
+ bool isFirst = true;
+ detail::FieldInfo prev;
+ for (const Block& element : wire.elements()) {
+ detail::FieldInfo info(element.type());
+
+ if (!info.isRecognized && !info.canIgnore) {
+ throw Error("unknown field cannot be ignored");
+ }
+
+ if (!isFirst) {
+ if (info.tlvType == prev.tlvType && !info.isRepeatable) {
+ throw Error("non-repeatable field cannot be repeated");
+ }
+
+ else if (info.tlvType != prev.tlvType && !detail::compareFieldSortOrder(prev, info)) {
+ throw Error("fields are not in correct sort order");
+ }
+ }
+
+ isFirst = false;
+ prev = info;
+ }
+
+ m_wire = wire;
+}
+
+bool
+Packet::comparePos(const Block& first, const uint64_t second)
+{
+ detail::FieldInfo firstInfo(first.type());
+ detail::FieldInfo secondInfo(second);
+ return detail::compareFieldSortOrder(firstInfo, secondInfo);
+}
+
+} // namespace lp
+} // namespace ndn
\ No newline at end of file
diff --git a/src/lp/packet.hpp b/src/lp/packet.hpp
new file mode 100644
index 0000000..bf0cb01
--- /dev/null
+++ b/src/lp/packet.hpp
@@ -0,0 +1,224 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_LP_PACKET_HPP
+#define NDN_CXX_LP_PACKET_HPP
+
+#include "fields.hpp"
+
+namespace ndn {
+namespace lp {
+
+class Packet
+{
+public:
+ class Error : public ndn::tlv::Error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : ndn::tlv::Error(what)
+ {
+ }
+ };
+
+ Packet();
+
+ explicit
+ Packet(const Block& wire);
+
+ /**
+ * \brief append packet to encoder
+ */
+ template<encoding::Tag TAG>
+ size_t
+ wireEncode(EncodingImpl<TAG>& encoder) const;
+
+ /**
+ * \brief encode packet into wire format
+ */
+ const Block&
+ wireEncode() const;
+
+ /**
+ * \brief decode packet from wire format
+ */
+ void
+ wireDecode(const Block& wire);
+
+public: // field access
+ /**
+ * \return true if FIELD occurs one or more times
+ * \detail This is equivalent to count()>0
+ */
+ template<typename FIELD>
+ bool
+ has() const
+ {
+ return count<FIELD>() > 0;
+ }
+
+ /**
+ * \return number of occurrences of FIELD
+ */
+ template<typename FIELD>
+ size_t
+ count() const
+ {
+ m_wire.parse();
+
+ return std::count_if(m_wire.elements_begin(), m_wire.elements_end(),
+ [] (const Block& block) {
+ return block.type() == FIELD::TlvType::value; });
+ }
+
+ /**
+ * \return value of index-th occurrence of FIELD
+ * \throw std::out_of_range if index>=count()
+ */
+ template<typename FIELD>
+ typename FIELD::ValueType
+ get(size_t index = 0) const
+ {
+ m_wire.parse();
+
+ size_t count = 0;
+ for (const Block& element : m_wire.elements()) {
+ if (element.type() != FIELD::TlvType::value) {
+ continue;
+ }
+ if (count++ == index) {
+ return FIELD::decode(element);
+ }
+ }
+
+ throw std::out_of_range("Index out of range");
+ }
+
+ /**
+ * \return values of all occurrences of FIELD
+ */
+ template<typename FIELD>
+ std::vector<typename FIELD::ValueType>
+ list() const
+ {
+ std::vector<typename FIELD::ValueType> output;
+
+ m_wire.parse();
+
+ for (const Block& element : m_wire.elements()) {
+ if (element.type() != FIELD::TlvType::value) {
+ continue;
+ }
+ output.push_back(FIELD::decode(element));
+ }
+
+ return output;
+ }
+
+ /**
+ * \brief remove all occurrences of FIELD, and add a FIELD with value
+ * \detail This equivalent to clear() followed by add(value)
+ */
+ template<typename FIELD>
+ Packet&
+ set(const typename FIELD::ValueType& value)
+ {
+ clear<FIELD>();
+ return add<FIELD>(value);
+ }
+
+ /**
+ * \brief add a FIELD with value
+ * \throw std::length_error if field already exists and is not repeatable
+ */
+ template<typename FIELD>
+ Packet&
+ add(const typename FIELD::ValueType& value)
+ {
+ if (!FIELD::IsRepeatable::value && has<FIELD>()) {
+ throw std::length_error("Field cannot be repeated");
+ }
+
+ EncodingEstimator estimator;
+ size_t estimatedSize = FIELD::encode(estimator, value);
+ EncodingBuffer buffer(estimatedSize, 0);
+ FIELD::encode(buffer, value);
+ Block block = buffer.block();
+
+ Block::element_const_iterator pos = std::lower_bound(m_wire.elements_begin(),
+ m_wire.elements_end(),
+ FIELD::TlvType::value,
+ comparePos);
+ m_wire.insert(pos, block);
+
+ return *this;
+ }
+
+ /**
+ * \brief remove the index-th occurrence of FIELD
+ * \throw std::out_of_range if index>=count()
+ */
+ template<typename FIELD>
+ Packet&
+ remove(size_t index = 0)
+ {
+ m_wire.parse();
+
+ size_t count = 0;
+ for (Block::element_const_iterator it = m_wire.elements_begin(); it != m_wire.elements_end();
+ ++it) {
+ if (it->type() == FIELD::TlvType::value) {
+ if (count == index) {
+ m_wire.erase(it);
+ return *this;
+ }
+ count++;
+ }
+ }
+
+ throw std::out_of_range("Index out of range");
+ }
+
+ /**
+ * \brief remove all occurrences of FIELD
+ */
+ template<typename FIELD>
+ Packet&
+ clear()
+ {
+ m_wire.parse();
+ m_wire.remove(FIELD::TlvType::value);
+ return *this;
+ }
+
+private:
+ static bool
+ comparePos(const Block& first, const uint64_t second);
+
+private:
+ mutable Block m_wire;
+};
+
+} // namespace lp
+} // namespace ndn
+
+#endif // NDN_CXX_LP_PACKET_HPP
\ No newline at end of file
diff --git a/src/lp/sequence.hpp b/src/lp/sequence.hpp
new file mode 100644
index 0000000..ccfa1bc
--- /dev/null
+++ b/src/lp/sequence.hpp
@@ -0,0 +1,40 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Eric Newberry <enewberry@email.arizona.edu>
+ */
+
+#ifndef NDN_CXX_LP_SEQUENCE_HPP
+#define NDN_CXX_LP_SEQUENCE_HPP
+
+#include "../common.hpp"
+
+namespace ndn {
+namespace lp {
+
+/**
+ * \brief represents a sequence number
+ */
+typedef uint64_t Sequence;
+
+} // namespace lp
+} // namespace ndn
+
+#endif // NDN_CXX_LP_SEQUENCE_HPP
\ No newline at end of file
diff --git a/src/lp/tlv.hpp b/src/lp/tlv.hpp
index b07b793..3231660 100644
--- a/src/lp/tlv.hpp
+++ b/src/lp/tlv.hpp
@@ -17,8 +17,6 @@
* <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
- *
- * @author Eric Newberry <enewberry@email.arizona.edu>
*/
#ifndef NDN_CXX_LP_TLV_HPP
@@ -45,6 +43,28 @@
IncomingFaceId = 817
};
+enum {
+ /**
+ * \brief lower bound of 1-octet header field
+ */
+ HEADER1_MIN = 81,
+
+ /**
+ * \brief upper bound of 1-octet header field
+ */
+ HEADER1_MAX = 99,
+
+ /**
+ * \brief lower bound of 3-octet header field
+ */
+ HEADER3_MIN = 800,
+
+ /**
+ * \brief upper bound of 3-octet header field
+ */
+ HEADER3_MAX = 959
+};
+
} // namespace tlv
} // namespace lp
} // namespace ndn
diff --git a/tests/unit-tests/lp/packet.t.cpp b/tests/unit-tests/lp/packet.t.cpp
new file mode 100644
index 0000000..f532214
--- /dev/null
+++ b/tests/unit-tests/lp/packet.t.cpp
@@ -0,0 +1,339 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "lp/packet.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace lp {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(LpPacket)
+
+BOOST_AUTO_TEST_CASE(FieldAccess)
+{
+ Packet packet;
+
+ BOOST_CHECK(!packet.has<FragIndexField>());
+ BOOST_CHECK_EQUAL(0, packet.count<FragIndexField>());
+ BOOST_CHECK_NO_THROW(packet.set<FragIndexField>(1234));
+ BOOST_CHECK(packet.has<FragIndexField>());
+ BOOST_CHECK_THROW(packet.add<FragIndexField>(5678), std::length_error);
+ BOOST_CHECK_EQUAL(1, packet.count<FragIndexField>());
+ BOOST_CHECK_EQUAL(1234, packet.get<FragIndexField>(0));
+ BOOST_CHECK_THROW(packet.get<FragIndexField>(1), std::out_of_range);
+ BOOST_CHECK_THROW(packet.remove<FragIndexField>(1), std::out_of_range);
+ BOOST_CHECK_NO_THROW(packet.remove<FragIndexField>(0));
+ BOOST_CHECK_EQUAL(0, packet.count<FragIndexField>());
+ BOOST_CHECK_NO_THROW(packet.add<FragIndexField>(832));
+ std::vector<uint64_t> fragIndexes;
+ BOOST_REQUIRE_NO_THROW(fragIndexes = packet.list<FragIndexField>());
+ BOOST_CHECK_EQUAL(1, fragIndexes.size());
+ BOOST_CHECK_EQUAL(832, fragIndexes.at(0));
+ BOOST_CHECK_NO_THROW(packet.clear<FragIndexField>());
+ BOOST_CHECK_EQUAL(0, packet.count<FragIndexField>());
+}
+
+/// \todo test field access methods with a REPEATABLE field
+
+BOOST_AUTO_TEST_CASE(EncodeFragment)
+{
+ static const uint8_t expectedBlock[] = {
+ 0x64, 0x04, // LpPacket
+ 0x50, 0x02, // Fragment
+ 0x03, 0xe8,
+ };
+
+ Buffer buf(2);
+ buf[0] = 0x03;
+ buf[1] = 0xe8;
+
+ Packet packet;
+ BOOST_CHECK_NO_THROW(packet.add<FragmentField>(std::make_pair(buf.begin(), buf.end())));
+ Block wire;
+ BOOST_REQUIRE_NO_THROW(wire = packet.wireEncode());
+ BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock),
+ wire.begin(), wire.end());
+}
+
+BOOST_AUTO_TEST_CASE(EncodeSubTlv)
+{
+ static const uint8_t expectedBlock[] = {
+ 0x64, 0x09, // LpPacket
+ 0xfd, 0x03, 0x20, 0x05, // Nack
+ 0xfd, 0x03, 0x21, 0x01, // NackReason
+ 0x64,
+ };
+
+ NackHeader nack;
+ nack.setReason(NackReason::DUPLICATE);
+
+ Packet packet;
+ BOOST_CHECK_NO_THROW(packet.add<NackField>(nack));
+ Block wire;
+ BOOST_REQUIRE_NO_THROW(wire = packet.wireEncode());
+ BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock),
+ wire.begin(), wire.end());
+}
+
+BOOST_AUTO_TEST_CASE(EncodeSortOrder)
+{
+ static const uint8_t expectedBlock[] = {
+ 0x64, 0x0a, // LpPacket
+ 0x52, 0x01, // FragIndex
+ 0x00,
+ 0x53, 0x01, // FragCount
+ 0x01,
+ 0x50, 0x02, // Fragment
+ 0x03, 0xe8,
+ };
+
+ Buffer frag(2);
+ frag[0] = 0x03;
+ frag[1] = 0xe8;
+
+ Packet packet;
+ BOOST_CHECK_NO_THROW(packet.add<FragmentField>(std::make_pair(frag.begin(), frag.end())));
+ BOOST_CHECK_NO_THROW(packet.add<FragIndexField>(0));
+ BOOST_CHECK_NO_THROW(packet.add<FragCountField>(1));
+ Block wire;
+ BOOST_REQUIRE_NO_THROW(wire = packet.wireEncode());
+ BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock),
+ wire.begin(), wire.end());
+}
+
+BOOST_AUTO_TEST_CASE(DecodeNormal)
+{
+ static const uint8_t inputBlock[] = {
+ 0x64, 0x0a, // LpPacket
+ 0x52, 0x01, // FragIndex
+ 0x00,
+ 0x53, 0x01, // FragCount
+ 0x01,
+ 0x50, 0x02, // Fragment
+ 0x03, 0xe8,
+ };
+
+ Packet packet;
+ Block wire(inputBlock, sizeof(inputBlock));
+ BOOST_CHECK_NO_THROW(packet.wireDecode(wire));
+ BOOST_CHECK_EQUAL(1, packet.count<FragmentField>());
+ BOOST_CHECK_EQUAL(1, packet.count<FragIndexField>());
+ BOOST_CHECK_EQUAL(1, packet.count<FragCountField>());
+ Buffer::const_iterator first, last;
+ BOOST_REQUIRE_NO_THROW(std::tie(first, last) = packet.get<FragmentField>(0));
+ BOOST_CHECK_EQUAL(2, last - first);
+ BOOST_CHECK_EQUAL(0x03, *first);
+ BOOST_CHECK_EQUAL(0xe8, *(last - 1));
+ BOOST_CHECK_EQUAL(0, packet.get<FragIndexField>(0));
+ BOOST_CHECK_EQUAL(1, packet.get<FragCountField>(0));
+}
+
+BOOST_AUTO_TEST_CASE(DecodeIdle)
+{
+ static const uint8_t inputBlock[] = {
+ 0x64, 0x06, // LpPacket
+ 0x52, 0x01, // FragIndex
+ 0x00,
+ 0x53, 0x01, // FragCount
+ 0x01,
+ };
+
+ Packet packet;
+ Block wire(inputBlock, sizeof(inputBlock));
+ BOOST_CHECK_NO_THROW(packet.wireDecode(wire));
+ BOOST_CHECK_EQUAL(0, packet.count<FragmentField>());
+ BOOST_CHECK_EQUAL(1, packet.count<FragIndexField>());
+ BOOST_CHECK_EQUAL(1, packet.count<FragCountField>());
+ BOOST_CHECK_EQUAL(0, packet.get<FragIndexField>(0));
+ BOOST_CHECK_EQUAL(1, packet.get<FragCountField>(0));
+}
+
+BOOST_AUTO_TEST_CASE(DecodeFragment)
+{
+ static const uint8_t inputBlock[] = {
+ 0x64, 0x04, // LpPacket
+ 0x50, 0x02, // Fragment
+ 0x03, 0xe8,
+ };
+
+ Packet packet;
+ Block wire(inputBlock, sizeof(inputBlock));
+ BOOST_CHECK_NO_THROW(packet.wireDecode(wire));
+ BOOST_CHECK_EQUAL(1, packet.count<FragmentField>());
+ BOOST_CHECK_EQUAL(0, packet.count<FragIndexField>());
+ Buffer::const_iterator first, last;
+ BOOST_REQUIRE_NO_THROW(std::tie(first, last) = packet.get<FragmentField>(0));
+ BOOST_CHECK_EQUAL(2, last - first);
+ BOOST_CHECK_EQUAL(0x03, *first);
+ BOOST_CHECK_EQUAL(0xe8, *(last - 1));
+}
+
+BOOST_AUTO_TEST_CASE(DecodeEmpty)
+{
+ static const uint8_t inputBlock[] = {
+ 0x64, 0x00, // LpPacket
+ };
+
+ Packet packet;
+ Block wire(inputBlock, sizeof(inputBlock));
+ BOOST_CHECK_NO_THROW(packet.wireDecode(wire));
+ BOOST_CHECK_EQUAL(0, packet.count<FragmentField>());
+ BOOST_CHECK_EQUAL(0, packet.count<FragIndexField>());
+}
+
+BOOST_AUTO_TEST_CASE(DecodeRepeatedNonRepeatableHeader)
+{
+ static const uint8_t inputBlock[] = {
+ 0x64, 0x06, // LpPacket
+ 0x52, 0x01, // FragIndex
+ 0x00,
+ 0x52, 0x01, // FragIndex
+ 0x01,
+ };
+
+ Packet packet;
+ Block wire(inputBlock, sizeof(inputBlock));
+ BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error);
+}
+
+BOOST_AUTO_TEST_CASE(DecodeRepeatedFragment)
+{
+ static const uint8_t inputBlock[] = {
+ 0x64, 0x08, // LpPacket
+ 0x50, 0x02, // Fragment
+ 0x03, 0xe8,
+ 0x50, 0x02, // Fragment
+ 0x03, 0xe9,
+ };
+
+ Packet packet;
+ Block wire(inputBlock, sizeof(inputBlock));
+ BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error);
+}
+
+BOOST_AUTO_TEST_CASE(DecodeWrongOrderAmongHeaders)
+{
+ static const uint8_t inputBlock[] = {
+ 0x64, 0x0a, // LpPacket
+ 0x53, 0x01, // FragCount
+ 0x01,
+ 0x52, 0x01, // FragIndex
+ 0x00,
+ 0x50, 0x02, // Fragment
+ 0x03, 0xe8,
+ };
+
+ Packet packet;
+ Block wire(inputBlock, sizeof(inputBlock));
+ BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error);
+}
+
+BOOST_AUTO_TEST_CASE(DecodeWrongOrderFragment)
+{
+ static const uint8_t inputBlock[] = {
+ 0x64, 0x0a, // LpPacket
+ 0x52, 0x01, // FragIndex
+ 0x00,
+ 0x50, 0x02, // Fragment
+ 0x03, 0xe8,
+ 0x53, 0x01, // FragCount
+ 0x01,
+ };
+
+ Packet packet;
+ Block wire(inputBlock, sizeof(inputBlock));
+ BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error);
+}
+
+BOOST_AUTO_TEST_CASE(DecodeIgnoredHeader)
+{
+ static const uint8_t inputBlock[] = {
+ 0x64, 0x0c, // LpPacket
+ 0x52, 0x01, // FragIndex
+ 0x00,
+ 0xfd, 0x03, 0x23, 0x01, // unknown TLV-TYPE 803 (ignored)
+ 0x02,
+ 0x50, 0x02, // Fragment
+ 0x03, 0xe8,
+ };
+
+ Packet packet;
+ Block wire(inputBlock, sizeof(inputBlock));
+ BOOST_CHECK_NO_THROW(packet.wireDecode(wire));
+ BOOST_CHECK_EQUAL(1, packet.count<FragmentField>());
+ BOOST_CHECK_EQUAL(1, packet.count<FragIndexField>());
+}
+
+BOOST_AUTO_TEST_CASE(DecodeUnrecognizedHeader)
+{
+ static const uint8_t inputBlock[] = {
+ 0x64, 0x0c, // LpPacket
+ 0x52, 0x01, // FragIndex
+ 0x00,
+ 0xfd, 0x03, 0x22, 0x01, // unknown TLV-TYPE 802 (cannot ignore)
+ 0x02,
+ 0x50, 0x02, // Fragment
+ 0x03, 0xe8,
+ };
+
+ Packet packet;
+ Block wire(inputBlock, sizeof(inputBlock));
+ BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error);
+}
+
+BOOST_AUTO_TEST_CASE(DecodeBareNetworkLayerPacket)
+{
+ static const uint8_t inputBlock[] = {
+ 0x05, 0x0a, // Interest
+ 0x07, 0x02, // Name
+ 0x03, 0xe8,
+ 0x0a, 0x04, // Nonce
+ 0x01, 0x02, 0x03, 0x04,
+ };
+
+ Packet packet;
+ Block wire(inputBlock, sizeof(inputBlock));
+ BOOST_CHECK_NO_THROW(packet.wireDecode(wire));
+ BOOST_CHECK_EQUAL(1, packet.count<FragmentField>());
+
+ static const uint8_t expectedBlock[] = {
+ 0x64, 0x0e, // LpPacket
+ 0x50, 0x0c, // Fragment
+ 0x05, 0x0a, // Interest
+ 0x07, 0x02, // Name
+ 0x03, 0xe8,
+ 0x0a, 0x04, // Nonce
+ 0x01, 0x02, 0x03, 0x04,
+ };
+
+ Block encoded;
+ BOOST_CHECK_NO_THROW(encoded = packet.wireEncode());
+ BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock),
+ encoded.begin(), encoded.end());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace lp
+} // namespace ndn
\ No newline at end of file