diff --git a/ndn-cxx/data.cpp b/ndn-cxx/data.cpp index 2e45a837..3167fc60 100644 --- a/ndn-cxx/data.cpp +++ b/ndn-cxx/data.cpp @@ -44,10 +44,25 @@ Data::wireEncode(EncodingImpl& encoder, bool wantUnsignedPortionOnly) const // [Content] // SignatureInfo // SignatureValue + // [ServiceClass] + // [TargetRate] // (elements are encoded in reverse order) size_t totalLength = 0; + // TargetRate + if (getTargetRate()) { + uint64_t targetRate = *getTargetRate(); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::TargetRate, targetRate); + // totalLength += encoder.prependByteArrayBlock(tlv::TargetRate, reinterpret_cast(&targetRate), sizeof(targetRate)); + } + // ServiceClass + if (getServiceClass()) { + uint8_t serviceClass = *getServiceClass(); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::ServiceClass, serviceClass); + // totalLength += encoder.prependByteArrayBlock(tlv::ServiceClass, reinterpret_cast(&serviceClass), sizeof(serviceClass)); + } + // SignatureValue if (!wantUnsignedPortionOnly) { if (!m_signatureInfo) { @@ -129,6 +144,8 @@ Data::wireDecode(const Block& wire) // [Content] // SignatureInfo // SignatureValue + // [ServiceClass] + // [TargetRate] auto element = m_wire.elements_begin(); if (element == m_wire.elements_end() || element->type() != tlv::Name) { @@ -177,6 +194,30 @@ Data::wireDecode(const Block& wire) lastElement = 5; break; } + case tlv::ServiceClass: { + if (lastElement >= 6) { + break; // ServiceClass is non-critical, ignore out-of-order appearance + } + if (element->value_size() != 1) { + NDN_THROW(Error("ServiceClass element is malformed")); + } + m_serviceClass = *element->value(); + lastElement = 6; + break; + } + case tlv::TargetRate: { + if (lastElement >= 7) { + break; // TargetRate is non-critical, ignore out-of-order appearance + } + uint64_t targetRate = 0; + if (element->value_size() != 8) { + NDN_THROW(Error("TargetRate element is malformed")); + } + std::memcpy(&targetRate, element->value(), sizeof(targetRate)); + m_targetRate = targetRate; + lastElement = 7; + break; + } default: { // unrecognized element // if the TLV-TYPE is critical, abort decoding if (tlv::isCriticalType(element->type())) { @@ -333,6 +374,25 @@ Data::extractSignedRanges() const return bufs; } +const Data& +Data::setServiceClass(std::optional serviceClass) const +{ + if (m_serviceClass != serviceClass) { + m_serviceClass = serviceClass; + m_wire.reset(); + } + return *this; +} +const Data& +Data::setTargetRate(std::optional targetRate) const +{ + if (m_targetRate != targetRate) { + m_targetRate = targetRate; + m_wire.reset(); + } + return *this; +} + Data& Data::setContentType(uint32_t type) { @@ -390,3 +450,4 @@ operator<<(std::ostream& os, const Data& data) } } // namespace ndn + diff --git a/ndn-cxx/data.hpp b/ndn-cxx/data.hpp index ac8ef0ac..c8dfd5c9 100644 --- a/ndn-cxx/data.hpp +++ b/ndn-cxx/data.hpp @@ -300,6 +300,22 @@ public: // Data fields [[nodiscard]] InputBuffers extractSignedRanges() const; + std::optional + getServiceClass() const noexcept + { + return m_serviceClass; + } + const Data& + setServiceClass(std::optional serviceClass) const; + + std::optional + getTargetRate() const noexcept + { + return m_targetRate; + } + const Data& + setTargetRate(std::optional targetRate) const; + public: // MetaInfo fields uint32_t getContentType() const @@ -365,6 +381,9 @@ private: Block m_content; SignatureInfo m_signatureInfo; Block m_signatureValue; + // Add for QSCCP + mutable std::optional m_serviceClass; + mutable std::optional m_targetRate; mutable Block m_wire; mutable Name m_fullName; // cached FullName computed from m_wire @@ -393,3 +412,4 @@ operator!=(const Data& lhs, const Data& rhs) } // namespace ndn #endif // NDN_CXX_DATA_HPP + diff --git a/ndn-cxx/encoding/tlv.hpp b/ndn-cxx/encoding/tlv.hpp index 43a603bb..4efd70c1 100644 --- a/ndn-cxx/encoding/tlv.hpp +++ b/ndn-cxx/encoding/tlv.hpp @@ -85,6 +85,10 @@ enum : uint32_t { Nonce = 10, InterestLifetime = 12, HopLimit = 34, + ServiceClass = 129, + DownstreamRate = 130, + TargetRate = 131, + Dsz = 132, ApplicationParameters = 36, InterestSignatureInfo = 44, InterestSignatureValue = 46, @@ -438,3 +442,4 @@ sizeOfNonNegativeInteger(uint64_t integer) noexcept } // namespace ndn #endif // NDN_CXX_ENCODING_TLV_HPP + diff --git a/ndn-cxx/interest.cpp b/ndn-cxx/interest.cpp index 4dfde5cb..522e2124 100644 --- a/ndn-cxx/interest.cpp +++ b/ndn-cxx/interest.cpp @@ -60,6 +60,9 @@ Interest::wireEncode(EncodingImpl& encoder) const // [Nonce] // [InterestLifetime] // [HopLimit] + // [Dsz] + // [ServiceClass] + // [DownstreamRate] // [ApplicationParameters [InterestSignature]] // (elements are encoded in reverse order) @@ -81,6 +84,25 @@ Interest::wireEncode(EncodingImpl& encoder) const totalLength += prependBlock(encoder, block); } + // DownstreamRate + if (getDownstreamRate()) { + uint64_t downstreamRate = *getDownstreamRate(); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::DownstreamRate, downstreamRate); + // totalLength += encoder.prependByteArrayBlock(tlv::DownstreamRate, reinterpret_cast(&downstreamRate), sizeof(downstreamRate)); + } + // ServiceClass + if (getServiceClass()) { + uint8_t serviceClass = *getServiceClass(); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::ServiceClass, serviceClass); + // totalLength += encoder.prependByteArrayBlock(tlv::ServiceClass, reinterpret_cast(&serviceClass), sizeof(serviceClass)); + } + // Dsz + if (getDsz()) { + uint16_t dsz = *getDsz(); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::Dsz, dsz); + // totalLength += encoder.prependByteArrayBlock(tlv::Dsz, reinterpret_cast(&dsz), sizeof(dsz)); + } + // HopLimit if (getHopLimit()) { totalLength += prependBinaryBlock(encoder, tlv::HopLimit, {*m_hopLimit}); @@ -156,6 +178,9 @@ Interest::wireDecode(const Block& wire) // [Nonce] // [InterestLifetime] // [HopLimit] + // [Dsz] + // [ServiceClass] + // [DownstreamRate] // [ApplicationParameters [InterestSignature]] auto element = m_wire.elements_begin(); @@ -179,6 +204,9 @@ Interest::wireDecode(const Block& wire) m_nonce.reset(); m_interestLifetime = DEFAULT_INTEREST_LIFETIME; m_hopLimit.reset(); + m_serviceClass.reset(); + m_downstreamRate.reset(); + m_dsz.reset(); m_parameters.clear(); int lastElement = 1; // last recognized element index, in spec order @@ -277,13 +305,50 @@ Interest::wireDecode(const Block& wire) lastElement = 7; break; } - case tlv::ApplicationParameters: { + case tlv::Dsz: { if (lastElement >= 8) { + break; // Dsz is non-critical, ignore out-of-order appearance + } + if (element->value_size() != 2) { + NDN_THROW(Error("Dsz element is malformed")); + } + uint16_t dsz = 0; + std::memcpy(&dsz, element->value(), sizeof(dsz)); + m_dsz = dsz; + lastElement = 8; + break; + } + case tlv::ServiceClass: { + if (lastElement >= 9) { + break; // ServiceClass is non-critical, ignore out-of-order appearance + } + if (element->value_size() != 1) { + NDN_THROW(Error("ServiceClass element is malformed" + std::to_string(element->value_size()))); + } + m_serviceClass = *element->value(); + lastElement = 9; + break; + } + case tlv::DownstreamRate: { + if (lastElement >= 10) { + break; // DownstreamRate is non-critical, ignore out-of-order appearance + } + uint64_t downstreamRate = 0; + if (element->value_size() != 8) { + NDN_THROW(Error("DownstreamRate element is malformed")); + } + std::memcpy(&downstreamRate, element->value(), sizeof(downstreamRate)); + m_downstreamRate = downstreamRate; + lastElement = 10; + break; + } + case tlv::ApplicationParameters: { + if (lastElement >= 11) { break; // ApplicationParameters is non-critical, ignore out-of-order appearance } BOOST_ASSERT(!hasApplicationParameters()); m_parameters.push_back(*element); - lastElement = 8; + lastElement = 11; break; } default: { // unrecognized element @@ -397,6 +462,34 @@ Interest::setForwardingHint(std::vector value) return *this; } +const Interest& +Interest::setServiceClass(std::optional serviceClass) const +{ + if (m_serviceClass != serviceClass) { + m_serviceClass = serviceClass; + m_wire.reset(); + } + return *this; +} +const Interest& +Interest::setDownstreamRate(std::optional downstreamRate) const +{ + if (m_downstreamRate != downstreamRate) { + m_downstreamRate = downstreamRate; + m_wire.reset(); + } + return *this; +} +const Interest& +Interest::setDsz(std::optional dsz) const +{ + if (m_dsz != dsz) { + m_dsz = dsz; + m_wire.reset(); + } + return *this; +} + [[nodiscard]] static auto generateNonce() { @@ -793,3 +886,4 @@ operator<<(std::ostream& os, const Interest& interest) } } // namespace ndn + diff --git a/ndn-cxx/interest.hpp b/ndn-cxx/interest.hpp index 7b817ab7..c446222a 100644 --- a/ndn-cxx/interest.hpp +++ b/ndn-cxx/interest.hpp @@ -254,6 +254,33 @@ public: // Interest fields Interest& setNonce(std::optional nonce); + std::optional + getServiceClass() const noexcept + { + return m_serviceClass; + } + + const Interest& + setServiceClass(std::optional serviceClass) const; + + std::optional + getDownstreamRate() const noexcept + { + return m_downstreamRate; + } + + const Interest& + setDownstreamRate(std::optional downstreamRate) const; + + std::optional + getDsz() const noexcept + { + return m_dsz; + } + + const Interest& + setDsz(std::optional dsz) const; + /** * @brief Change nonce value. * @@ -508,6 +535,10 @@ private: Name m_name; std::vector m_forwardingHint; mutable std::optional m_nonce; + // Add for QSCCP + mutable std::optional m_serviceClass; + mutable std::optional m_downstreamRate; + mutable std::optional m_dsz; time::milliseconds m_interestLifetime = DEFAULT_INTEREST_LIFETIME; std::optional m_hopLimit; bool m_canBePrefix = false; @@ -534,3 +565,4 @@ operator<<(std::ostream& os, const Interest& interest); } // namespace ndn #endif // NDN_CXX_INTEREST_HPP + diff --git a/ndn-cxx/lp/fields.hpp b/ndn-cxx/lp/fields.hpp index 37cbec42..2390fc22 100644 --- a/ndn-cxx/lp/fields.hpp +++ b/ndn-cxx/lp/fields.hpp @@ -114,6 +114,37 @@ typedef FieldDecl PrefixAnnouncementField; +/** + * DSZ Field + * Data Size field + */ +typedef FieldDecl DSZField; + +/** + * Tos Field + */ +typedef FieldDecl TosField; + +/** + * Fair rate field + */ +typedef FieldDecl TargetRateField; + +///** +// * Queue occupy rate +// */ +//typedef FieldDecl QueueOccupyRateField; +//BOOST_CONCEPT_ASSERT((Field)); +/** + * Available rate field + */ +typedef FieldDecl DownstreamRateField; + /** * \brief Set of all field declarations. */ @@ -131,7 +162,12 @@ using FieldSet = boost::mp11::mp_list< AckField, TxSequenceField, NonDiscoveryField, - PrefixAnnouncementField + PrefixAnnouncementField, + DSZField, + TosField, + TargetRateField, +// QueueOccupyRateField, + DownstreamRateField >; static_assert(boost::mp11::mp_is_set
()); diff --git a/ndn-cxx/lp/tags.hpp b/ndn-cxx/lp/tags.hpp index 312a39da..45a513d6 100644 --- a/ndn-cxx/lp/tags.hpp +++ b/ndn-cxx/lp/tags.hpp @@ -77,6 +77,31 @@ using NonDiscoveryTag = SimpleTag; */ using PrefixAnnouncementTag = SimpleTag; +/** + * DSZ + * Data Size + */ +using DSZTag = SimpleTag; + +/** + * Tos + */ +using TosTag = SimpleTag; + +/** + * Fair rate tag + */ +using FairRateTag = SimpleTag; +///** +// * Queue occupy rate(0 ~ 100) +// */ +//typedef SimpleTag QueueOccupyRateTag; +/** + * Available Rate tag + */ +using DownstreamRateTag = SimpleTag; +// typedef SimpleTag DownstreamRateTag; + } // namespace ndn::lp #endif // NDN_CXX_LP_TAGS_HPP diff --git a/ndn-cxx/lp/tlv.hpp b/ndn-cxx/lp/tlv.hpp index 10fe1f6e..86288406 100644 --- a/ndn-cxx/lp/tlv.hpp +++ b/ndn-cxx/lp/tlv.hpp @@ -52,6 +52,18 @@ enum : uint32_t { NonDiscovery = 844, PrefixAnnouncement = 848, + + // Add DSZ Tag + DSZ = 852, + // Add Tos Tag + Tos = 856, + // Add Target Rate + TargetRate = 890, +// // Add queue occupy rate +// QueueOccupyRate = 894, + // Add Downstream Rate + DownstreamRate = 894, + /** * \brief Lower bound of 1-octet header field. */