| /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */ |
| /* |
| * Copyright (c) 2011 University of California, Los Angeles |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation; |
| * |
| * This program 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 General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| * |
| * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu> |
| */ |
| |
| #include "ndn-encoding-helper.h" |
| |
| #include "ns3/ndn-name-components.h" |
| #include "ns3/ndn-interest-header.h" |
| #include "ns3/ndn-content-object-header.h" |
| |
| #include <sstream> |
| #include <boost/foreach.hpp> |
| |
| namespace ns3 { |
| namespace ndn { |
| |
| size_t |
| EncodingHelper::Serialize (Buffer::Iterator start, const InterestHeader &interest) |
| { |
| size_t written = 0; |
| written += AppendBlockHeader (start, CcnbParser::CCN_DTAG_Interest, CcnbParser::CCN_DTAG); // <Interest> |
| |
| written += AppendBlockHeader (start, CcnbParser::CCN_DTAG_Name, CcnbParser::CCN_DTAG); // <Name> |
| written += AppendNameComponents (start, interest.GetName()); // <Component>...</Component>... |
| written += AppendCloser (start); // </Name> |
| |
| if (interest.GetMinSuffixComponents() >= 0) |
| { |
| written += AppendBlockHeader (start, CcnbParser::CCN_DTAG_MinSuffixComponents, CcnbParser::CCN_DTAG); |
| written += AppendNumber (start, interest.GetMinSuffixComponents ()); |
| written += AppendCloser (start); |
| } |
| if (interest.GetMaxSuffixComponents() >= 0) |
| { |
| written += AppendBlockHeader (start, CcnbParser::CCN_DTAG_MaxSuffixComponents, CcnbParser::CCN_DTAG); |
| written += AppendNumber (start, interest.GetMaxSuffixComponents ()); |
| written += AppendCloser (start); |
| } |
| if (interest.IsEnabledExclude() && interest.GetExclude().size() > 0) |
| { |
| written += AppendBlockHeader (start, CcnbParser::CCN_DTAG_Exclude, CcnbParser::CCN_DTAG); // <Exclude> |
| written += AppendNameComponents (start, interest.GetExclude()); // <Component>...</Component>... |
| written += AppendCloser (start); // </Exclude> |
| } |
| if (interest.IsEnabledChildSelector()) |
| { |
| written += AppendBlockHeader (start, CcnbParser::CCN_DTAG_ChildSelector, CcnbParser::CCN_DTAG); |
| written += AppendNumber (start, 1); |
| written += AppendCloser (start); |
| } |
| if (interest.IsEnabledAnswerOriginKind()) |
| { |
| written += AppendBlockHeader (start, CcnbParser::CCN_DTAG_AnswerOriginKind, CcnbParser::CCN_DTAG); |
| written += AppendNumber (start, 1); |
| written += AppendCloser (start); |
| } |
| if (interest.GetScope() >= 0) |
| { |
| written += AppendBlockHeader (start, CcnbParser::CCN_DTAG_Scope, CcnbParser::CCN_DTAG); |
| written += AppendNumber (start, interest.GetScope ()); |
| written += AppendCloser (start); |
| } |
| if (!interest.GetInterestLifetime().IsZero()) |
| { |
| written += AppendBlockHeader (start, CcnbParser::CCN_DTAG_InterestLifetime, CcnbParser::CCN_DTAG); |
| written += AppendTimestampBlob (start, interest.GetInterestLifetime ()); |
| written += AppendCloser (start); |
| } |
| if (interest.GetNonce()>0) |
| { |
| uint32_t nonce = interest.GetNonce(); |
| written += AppendTaggedBlob (start, CcnbParser::CCN_DTAG_Nonce, nonce); |
| } |
| |
| if (interest.GetNack ()>0) |
| { |
| written += AppendBlockHeader (start, CcnbParser::CCN_DTAG_Nack, CcnbParser::CCN_DTAG); |
| written += AppendNumber (start, interest.GetNack ()); |
| written += AppendCloser (start); |
| } |
| written += AppendCloser (start); // </Interest> |
| |
| return written; |
| } |
| |
| size_t |
| EncodingHelper::GetSerializedSize (const InterestHeader &interest) |
| { |
| size_t written = 0; |
| written += EstimateBlockHeader (CcnbParser::CCN_DTAG_Interest); // <Interest> |
| |
| written += EstimateBlockHeader (CcnbParser::CCN_DTAG_Name); // <Name> |
| written += EstimateNameComponents (interest.GetName()); // <Component>...</Component>... |
| written += 1; // </Name> |
| |
| if (interest.GetMinSuffixComponents() >= 0) |
| { |
| written += EstimateBlockHeader (CcnbParser::CCN_DTAG_MinSuffixComponents); |
| written += EstimateNumber (interest.GetMinSuffixComponents ()); |
| written += 1; |
| } |
| if (interest.GetMaxSuffixComponents() >= 0) |
| { |
| written += EstimateBlockHeader (CcnbParser::CCN_DTAG_MaxSuffixComponents); |
| written += EstimateNumber (interest.GetMaxSuffixComponents ()); |
| written += 1; |
| } |
| if (interest.IsEnabledExclude() && interest.GetExclude().size() > 0) |
| { |
| written += EstimateBlockHeader (CcnbParser::CCN_DTAG_Exclude); |
| written += EstimateNameComponents (interest.GetExclude()); // <Component>...</Component>... |
| written += 1; // </Exclude> |
| } |
| if (interest.IsEnabledChildSelector()) |
| { |
| written += EstimateBlockHeader (CcnbParser::CCN_DTAG_ChildSelector); |
| written += EstimateNumber (1); |
| written += 1; |
| } |
| if (interest.IsEnabledAnswerOriginKind()) |
| { |
| written += EstimateBlockHeader (CcnbParser::CCN_DTAG_AnswerOriginKind); |
| written += EstimateNumber (1); |
| written += 1; |
| } |
| if (interest.GetScope() >= 0) |
| { |
| written += EstimateBlockHeader (CcnbParser::CCN_DTAG_Scope); |
| written += EstimateNumber (interest.GetScope ()); |
| written += 1; |
| } |
| if (!interest.GetInterestLifetime().IsZero()) |
| { |
| written += EstimateBlockHeader (CcnbParser::CCN_DTAG_InterestLifetime); |
| written += EstimateTimestampBlob (interest.GetInterestLifetime()); |
| written += 1; |
| } |
| if (interest.GetNonce()>0) |
| { |
| written += EstimateTaggedBlob (CcnbParser::CCN_DTAG_Nonce, sizeof(uint32_t)); |
| } |
| if (interest.GetNack ()>0) |
| { |
| written += EstimateBlockHeader (CcnbParser::CCN_DTAG_Nack); |
| written += EstimateNumber (interest.GetNack ()); |
| written += 1; |
| } |
| |
| written += 1; // </Interest> |
| |
| return written; |
| } |
| |
| ////////////////////////////////////////////////////////////////////// |
| ////////////////////////////////////////////////////////////////////// |
| ////////////////////////////////////////////////////////////////////// |
| |
| #define CCN_TT_BITS 3 |
| #define CCN_TT_MASK ((1 << CCN_TT_BITS) - 1) |
| #define CCN_MAX_TINY ((1 << (7-CCN_TT_BITS)) - 1) |
| #define CCN_TT_HBIT ((unsigned char)(1 << 7)) |
| |
| size_t |
| EncodingHelper::AppendBlockHeader (Buffer::Iterator &start, size_t val, CcnbParser::ccn_tt tt) |
| { |
| unsigned char buf[1+8*((sizeof(val)+6)/7)]; |
| unsigned char *p = &(buf[sizeof(buf)-1]); |
| size_t n = 1; |
| p[0] = (CCN_TT_HBIT & ~CcnbParser::CCN_CLOSE) | |
| ((val & CCN_MAX_TINY) << CCN_TT_BITS) | |
| (CCN_TT_MASK & tt); |
| val >>= (7-CCN_TT_BITS); |
| while (val != 0) { |
| (--p)[0] = (((unsigned char)val) & ~CCN_TT_HBIT) | CcnbParser::CCN_CLOSE; |
| n++; |
| val >>= 7; |
| } |
| start.Write (p,n); |
| return n; |
| } |
| |
| size_t |
| EncodingHelper::EstimateBlockHeader (size_t value) |
| { |
| value >>= (7-CCN_TT_BITS); |
| size_t n = 1; |
| while (value>0) |
| { |
| value >>= 7; |
| n++; |
| } |
| return n; |
| } |
| |
| size_t |
| EncodingHelper::AppendNumber (Buffer::Iterator &start, uint32_t number) |
| { |
| std::ostringstream os; |
| os << number; |
| |
| size_t written = 0; |
| written += AppendBlockHeader (start, os.str().size(), CcnbParser::CCN_UDATA); |
| written += os.str().size(); |
| start.Write (reinterpret_cast<const unsigned char*>(os.str().c_str()), os.str().size()); |
| |
| return written; |
| } |
| |
| size_t |
| EncodingHelper::EstimateNumber (uint32_t number) |
| { |
| std::ostringstream os; |
| os << number; |
| return EstimateBlockHeader (os.str ().size ()) + os.str ().size (); |
| } |
| |
| size_t |
| EncodingHelper::AppendCloser (Buffer::Iterator &start) |
| { |
| start.WriteU8 (CcnbParser::CCN_CLOSE); |
| return 1; |
| } |
| |
| size_t |
| EncodingHelper::AppendNameComponents (Buffer::Iterator &start, const NameComponents &name) |
| { |
| size_t written = 0; |
| BOOST_FOREACH (const std::string &component, name.GetComponents()) |
| { |
| written += AppendTaggedBlob (start, CcnbParser::CCN_DTAG_Component, |
| reinterpret_cast<const uint8_t*>(component.c_str()), component.size()); |
| } |
| return written; |
| } |
| |
| size_t |
| EncodingHelper::EstimateNameComponents (const NameComponents &name) |
| { |
| size_t written = 0; |
| BOOST_FOREACH (const std::string &component, name.GetComponents()) |
| { |
| written += EstimateTaggedBlob (CcnbParser::CCN_DTAG_Component, component.size()); |
| } |
| return written; |
| } |
| |
| size_t |
| EncodingHelper::AppendTimestampBlob (Buffer::Iterator &start, const Time &time) |
| { |
| // the original function implements Markers... thought not sure what are these markers for... |
| |
| // Determine miminal number of bytes required to store the timestamp |
| int required_bytes = 2; // 12 bits for fractions of a second, 4 bits left for seconds. Sometimes it is enough |
| intmax_t ts = time.ToInteger (Time::S) >> 4; |
| for (; required_bytes < 7 && ts != 0; ts >>= 8) // not more than 6 bytes? |
| required_bytes++; |
| |
| size_t len = AppendBlockHeader(start, required_bytes, CcnbParser::CCN_BLOB); |
| |
| // write part with seconds |
| ts = time.ToInteger (Time::S) >> 4; |
| for (int i = 0; i < required_bytes - 2; i++) |
| start.WriteU8 ( ts >> (8 * (required_bytes - 3 - i)) ); |
| |
| /* arithmetic contortions are to avoid overflowing 31 bits */ |
| ts = ((time.ToInteger (Time::S) & 15) << 12) + |
| (((time.ToInteger (Time::NS) % 1000000000) / 5 * 8 + 195312) / 390625); |
| for (int i = required_bytes - 2; i < required_bytes; i++) |
| start.WriteU8 ( ts >> (8 * (required_bytes - 1 - i)) ); |
| |
| return len + required_bytes; |
| } |
| |
| size_t |
| EncodingHelper::EstimateTimestampBlob (const Time &time) |
| { |
| int required_bytes = 2; // 12 bits for fractions of a second, 4 bits left for seconds. Sometimes it is enough |
| intmax_t ts = time.ToInteger (Time::S) >> 4; |
| for (; required_bytes < 7 && ts != 0; ts >>= 8) // not more than 6 bytes? |
| required_bytes++; |
| |
| return EstimateBlockHeader (required_bytes) + required_bytes; |
| } |
| |
| size_t |
| EncodingHelper::AppendTaggedBlob (Buffer::Iterator &start, CcnbParser::ccn_dtag dtag, |
| const uint8_t *data, size_t size) |
| { |
| size_t written = AppendBlockHeader (start, dtag, CcnbParser::CCN_DTAG); |
| /* 2 */ |
| if (size>0) |
| { |
| written += AppendBlockHeader (start, size, CcnbParser::CCN_BLOB); |
| start.Write (data, size); |
| written += size; |
| /* size */ |
| } |
| written += AppendCloser (start); |
| /* 1 */ |
| |
| return written; |
| } |
| |
| size_t |
| EncodingHelper::EstimateTaggedBlob (CcnbParser::ccn_dtag dtag, size_t size) |
| { |
| if (size>0) |
| return EstimateBlockHeader (dtag) + EstimateBlockHeader (size) + size + 1; |
| else |
| return EstimateBlockHeader (dtag) + 1; |
| } |
| |
| size_t |
| EncodingHelper::AppendString (Buffer::Iterator &start, CcnbParser::ccn_dtag dtag, |
| const std::string &string) |
| { |
| size_t written = AppendBlockHeader (start, dtag, CcnbParser::CCN_DTAG); |
| { |
| written += AppendBlockHeader (start, string.size (), CcnbParser::CCN_UDATA); |
| start.Write (reinterpret_cast<const uint8_t*> (string.c_str ()), string.size ()); |
| written += string.size (); |
| } |
| written += AppendCloser (start); |
| |
| return written; |
| } |
| |
| size_t |
| EncodingHelper::EstimateString (CcnbParser::ccn_dtag dtag, const std::string &string) |
| { |
| return EstimateBlockHeader (dtag) + EstimateBlockHeader (string.size ()) + string.size () + 1; |
| } |
| |
| |
| } // namespace ndn |
| } // namespace ns3 |