| /* -*- 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: Ilya Moiseenko <iliamo@cs.ucla.edu> |
| * Alexander Afanasyev <alexander.afanasyev@ucla.edu> |
| */ |
| |
| #include "../ccnb.h" |
| |
| #include "wire-ccnb.h" |
| |
| #include "ns3/log.h" |
| |
| #include "ccnb-parser/common.h" |
| #include "ccnb-parser/visitors/void-depth-first-visitor.h" |
| #include "ccnb-parser/visitors/name-visitor.h" |
| #include "ccnb-parser/visitors/non-negative-integer-visitor.h" |
| #include "ccnb-parser/visitors/timestamp-visitor.h" |
| #include "ccnb-parser/visitors/string-visitor.h" |
| #include "ccnb-parser/visitors/uint32t-blob-visitor.h" |
| #include "ccnb-parser/visitors/content-type-visitor.h" |
| |
| #include "ccnb-parser/syntax-tree/block.h" |
| #include "ccnb-parser/syntax-tree/dtag.h" |
| |
| #include <boost/foreach.hpp> |
| |
| NS_LOG_COMPONENT_DEFINE ("ndn.wire.Ccnb.Data"); |
| |
| NDN_NAMESPACE_BEGIN |
| |
| namespace wire { |
| namespace ccnb { |
| |
| // const std::string DefaultDigestAlgorithm = "2.16.840.1.101.3.4.2.1"; |
| |
| class DataTrailer : public Trailer |
| { |
| public: |
| DataTrailer () |
| { |
| } |
| |
| static TypeId GetTypeId () |
| { |
| static TypeId tid = TypeId ("ns3::ndn::Data::Ccnb::Closer") |
| .SetGroupName ("Ndn") |
| .SetParent<Trailer> () |
| .AddConstructor<DataTrailer> () |
| ; |
| return tid; |
| } |
| |
| virtual TypeId GetInstanceTypeId (void) const |
| { |
| return GetTypeId (); |
| } |
| |
| virtual void Print (std::ostream &os) const |
| { |
| } |
| |
| virtual uint32_t GetSerializedSize (void) const |
| { |
| return 2; |
| } |
| |
| virtual void Serialize (Buffer::Iterator end) const |
| { |
| Buffer::Iterator i = end; |
| i.Prev (2); // Trailer interface requires us to go backwards |
| |
| i.WriteU8 (0x00); // </Content> |
| i.WriteU8 (0x00); // </ContentObject> |
| } |
| |
| virtual uint32_t Deserialize (Buffer::Iterator end) |
| { |
| Buffer::Iterator i = end; |
| i.Prev (2); // Trailer interface requires us to go backwards |
| |
| uint8_t closing_tag_content = i.ReadU8 (); |
| NS_ASSERT_MSG (closing_tag_content==0, "Should be a closing tag </Content> (0x00)"); |
| |
| uint8_t closing_tag_content_object = i.ReadU8 (); |
| NS_ASSERT_MSG (closing_tag_content_object==0, "Should be a closing tag </ContentObject> (0x00)"); |
| |
| return 2; |
| } |
| }; |
| |
| NS_OBJECT_ENSURE_REGISTERED (Data); |
| NS_OBJECT_ENSURE_REGISTERED (DataTrailer); |
| |
| TypeId |
| Data::GetTypeId (void) |
| { |
| static TypeId tid = TypeId ("ns3::ndn::Data::Ccnb") |
| .SetGroupName ("Ndn") |
| .SetParent<Header> () |
| .AddConstructor<Data> () |
| ; |
| return tid; |
| } |
| |
| TypeId |
| Data::GetInstanceTypeId (void) const |
| { |
| return GetTypeId (); |
| } |
| |
| Data::Data () |
| : m_data (Create<ndn::ContentObject> ()) |
| { |
| } |
| |
| Data::Data (Ptr<ndn::ContentObject> data) |
| : m_data (data) |
| { |
| } |
| |
| Ptr<ndn::ContentObject> |
| Data::GetData () |
| { |
| return m_data; |
| } |
| |
| Ptr<Packet> |
| Data::ToWire (Ptr<const ndn::ContentObject> data) |
| { |
| static DataTrailer trailer; |
| |
| Ptr<const Packet> p = data->GetWire (); |
| if (!p) |
| { |
| Ptr<Packet> packet = Create<Packet> (*data->GetPayload ()); |
| Data wireEncoding (ConstCast<ndn::ContentObject> (data)); |
| packet->AddHeader (wireEncoding); |
| packet->AddTrailer (trailer); |
| data->SetWire (packet); |
| |
| p = packet; |
| } |
| |
| return p->Copy (); |
| } |
| |
| Ptr<ndn::ContentObject> |
| Data::FromWire (Ptr<Packet> packet) |
| { |
| static DataTrailer trailer; |
| |
| Ptr<ndn::ContentObject> data = Create<ndn::ContentObject> (); |
| data->SetWire (packet->Copy ()); |
| |
| Data wireEncoding (data); |
| packet->RemoveHeader (wireEncoding); |
| packet->RemoveTrailer (trailer); |
| |
| data->SetPayload (packet); |
| |
| return data; |
| } |
| |
| void |
| Data::Serialize (Buffer::Iterator start) const |
| { |
| Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_ContentObject, CcnbParser::CCN_DTAG); // <ContentObject> |
| |
| // fake signature |
| Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_Signature, CcnbParser::CCN_DTAG); // <Signature> |
| // Signature ::= √DigestAlgorithm? |
| // Witness? |
| // √SignatureBits |
| // if (GetSignature ().GetDigestAlgorithm () != Signature::DefaultDigestAlgorithm) |
| // { |
| // Ccnb::AppendString (start, CcnbParser::CCN_DTAG_DigestAlgorithm, GetSignature ().GetDigestAlgorithm ()); |
| // } |
| Ccnb::AppendTaggedBlob (start, CcnbParser::CCN_DTAG_SignatureBits, m_data->GetSignature ()); // <SignatureBits /> |
| Ccnb::AppendCloser (start); // </Signature> |
| |
| Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_Name, CcnbParser::CCN_DTAG); // <Name> |
| Ccnb::AppendName (start, m_data->GetName()); // <Component>...</Component>... |
| Ccnb::AppendCloser (start); // </Name> |
| |
| // fake signature |
| Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_SignedInfo, CcnbParser::CCN_DTAG); // <SignedInfo> |
| // SignedInfo ::= √PublisherPublicKeyDigest |
| // √Timestamp |
| // √Type? |
| // √FreshnessSeconds? |
| // FinalBlockID? |
| // KeyLocator? |
| // Ccnb::AppendTaggedBlob (start, CcnbParser::CCN_DTAG_PublisherPublicKeyDigest, // <PublisherPublicKeyDigest>... |
| // GetSignedInfo ().GetPublisherPublicKeyDigest ()); |
| |
| Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_Timestamp, CcnbParser::CCN_DTAG); // <Timestamp>... |
| Ccnb::AppendTimestampBlob (start, m_data->GetTimestamp ()); |
| Ccnb::AppendCloser (start); |
| |
| // if (GetSignedInfo ().GetContentType () != DATA) |
| // { |
| // uint8_t type[3]; |
| // type[0] = (GetSignedInfo ().GetContentType () >> 16) & 0xFF; |
| // type[1] = (GetSignedInfo ().GetContentType () >> 8 ) & 0xFF; |
| // type[2] = (GetSignedInfo ().GetContentType () ) & 0xFF; |
| |
| // Ccnb::AppendTaggedBlob (start, CCN_DTAG_Type, type, 3); |
| // } |
| if (m_data->GetFreshness () > Seconds(0)) |
| { |
| Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_FreshnessSeconds, CcnbParser::CCN_DTAG); |
| Ccnb::AppendNumber (start, m_data->GetFreshness ().ToInteger (Time::S)); |
| Ccnb::AppendCloser (start); |
| } |
| if (m_data->GetKeyLocator () != 0) |
| { |
| Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_KeyLocator, CcnbParser::CCN_DTAG); // <KeyLocator> |
| { |
| Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_KeyName, CcnbParser::CCN_DTAG); // <KeyName> |
| { |
| Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_Name, CcnbParser::CCN_DTAG); // <Name> |
| Ccnb::AppendName (start, *m_data->GetKeyLocator ()); // <Component>...</Component>... |
| Ccnb::AppendCloser (start); // </Name> |
| } |
| Ccnb::AppendCloser (start); // </KeyName> |
| } |
| Ccnb::AppendCloser (start); // </KeyLocator> |
| } |
| |
| Ccnb::AppendCloser (start); // </SignedInfo> |
| |
| Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_Content, CcnbParser::CCN_DTAG); // <Content> |
| |
| // there are no closing tags !!! |
| // The closing tag is handled by ContentObjectTail |
| } |
| |
| uint32_t |
| Data::GetSerializedSize () const |
| { |
| size_t written = 0; |
| written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_ContentObject); // <ContentObject> |
| |
| // fake signature |
| written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_Signature); // <Signature> |
| // Signature ::= DigestAlgorithm? |
| // Witness? |
| // SignatureBits |
| // if (GetSignature ().GetDigestAlgorithm () != Signature::DefaultDigestAlgorithm) |
| // { |
| // written += Ccnb::EstimateString (CcnbParser::CCN_DTAG_DigestAlgorithm, GetSignature ().GetDigestAlgorithm ()); |
| // } |
| written += Ccnb::EstimateTaggedBlob (CcnbParser::CCN_DTAG_SignatureBits, |
| sizeof (m_data->GetSignature ())); // <SignatureBits /> |
| written += 1; // </Signature> |
| |
| written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_Name); // <Name> |
| written += Ccnb::EstimateName (m_data->GetName ()); // <Component>...</Component>... |
| written += 1; // </Name> |
| |
| // fake signature |
| written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_SignedInfo); // <SignedInfo> |
| // SignedInfo ::= √PublisherPublicKeyDigest |
| // √Timestamp |
| // √Type? |
| // √FreshnessSeconds? |
| // FinalBlockID? |
| // KeyLocator? |
| |
| // written += Ccnb::EstimateTaggedBlob (CCN_DTAG_PublisherPublicKeyDigest, // <PublisherPublicKeyDigest>... |
| // sizeof (GetSignedInfo ().GetPublisherPublicKeyDigest ())); |
| |
| written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_Timestamp); // <Timestamp>... |
| written += Ccnb::EstimateTimestampBlob (m_data->GetTimestamp ()); |
| written += 1; |
| |
| // if (GetSignedInfo ().GetContentType () != DATA) |
| // { |
| // written += Ccnb::EstimateTaggedBlob (CcnbParser::CCN_DTAG_Type, 3); |
| // } |
| if (m_data->GetFreshness () > Seconds(0)) |
| { |
| written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_FreshnessSeconds); |
| written += Ccnb::EstimateNumber (m_data->GetFreshness ().ToInteger (Time::S)); |
| written += 1; |
| } |
| |
| if (m_data->GetKeyLocator () != 0) |
| { |
| written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_KeyLocator); // <KeyLocator> |
| { |
| written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_KeyName); // <KeyName> |
| { |
| written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_Name); // <Name> |
| written += Ccnb::EstimateName (*m_data->GetKeyLocator ()); // <Component>...</Component>... |
| written += 1; // </Name> |
| } |
| written += 1; // </KeyName> |
| } |
| written += 1; // </KeyLocator> |
| } |
| |
| written += 1; // </SignedInfo> |
| |
| written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_Content); // <Content> |
| |
| // there are no closing tags !!! |
| // The closing tag is handled by ContentObjectTail |
| return written; |
| } |
| |
| class ContentObjectVisitor : public CcnbParser::VoidDepthFirstVisitor |
| { |
| public: |
| virtual void visit (CcnbParser::Dtag &n, boost::any param/*should be ContentObject* */) |
| { |
| // uint32_t n.m_dtag; |
| // std::list< Ptr<CcnbParser::Block> > n.m_nestedBlocks; |
| static CcnbParser::NameVisitor nameVisitor; |
| static CcnbParser::NonNegativeIntegerVisitor nonNegativeIntegerVisitor; |
| static CcnbParser::TimestampVisitor timestampVisitor; |
| static CcnbParser::StringVisitor stringVisitor; |
| static CcnbParser::Uint32tBlobVisitor uint32tBlobVisitor; |
| static CcnbParser::ContentTypeVisitor contentTypeVisitor; |
| |
| ndn::ContentObject &contentObject = *(boost::any_cast<ndn::ContentObject*> (param)); |
| |
| switch (n.m_dtag) |
| { |
| case CcnbParser::CCN_DTAG_ContentObject: |
| // process nested blocks |
| BOOST_FOREACH (Ptr<CcnbParser::Block> block, n.m_nestedTags) |
| { |
| block->accept (*this, param); |
| } |
| break; |
| case CcnbParser::CCN_DTAG_Name: |
| { |
| // process name components |
| Ptr<Name> name = Create<Name> (); |
| |
| BOOST_FOREACH (Ptr<CcnbParser::Block> block, n.m_nestedTags) |
| { |
| block->accept (nameVisitor, &(*name)); |
| } |
| contentObject.SetName (name); |
| break; |
| } |
| |
| case CcnbParser::CCN_DTAG_Signature: |
| // process nested blocks |
| BOOST_FOREACH (Ptr<CcnbParser::Block> block, n.m_nestedTags) |
| { |
| block->accept (*this, param); |
| } |
| break; |
| |
| // case CCN_DTAG_DigestAlgorithm: |
| // NS_LOG_DEBUG ("DigestAlgorithm"); |
| // if (n.m_nestedTags.size ()!=1) // should be exactly one UDATA inside this tag |
| // throw CcnbParser::CcnbDecodingException (); |
| |
| // contentObject.GetSignature ().SetDigestAlgorithm |
| // (boost::any_cast<std::string> ((*n.m_nestedTags.begin())->accept |
| // (stringVisitor))); |
| // break; |
| |
| case CcnbParser::CCN_DTAG_SignatureBits: |
| NS_LOG_DEBUG ("SignatureBits"); |
| if (n.m_nestedTags.size ()!=1) // should be only one nested tag |
| throw CcnbParser::CcnbDecodingException (); |
| |
| contentObject.SetSignature |
| (boost::any_cast<uint32_t> ((*n.m_nestedTags.begin())->accept |
| (uint32tBlobVisitor))); |
| break; |
| |
| case CcnbParser::CCN_DTAG_SignedInfo: |
| // process nested blocks |
| BOOST_FOREACH (Ptr<CcnbParser::Block> block, n.m_nestedTags) |
| { |
| block->accept (*this, param); |
| } |
| break; |
| |
| // case CCN_DTAG_PublisherPublicKeyDigest: |
| // NS_LOG_DEBUG ("PublisherPublicKeyDigest"); |
| // if (n.m_nestedTags.size ()!=1) // should be only one nested tag |
| // throw CcnbParser::CcnbDecodingException (); |
| |
| // contentObject.GetSignedInfo ().SetPublisherPublicKeyDigest |
| // (boost::any_cast<uint32_t> ((*n.m_nestedTags.begin())->accept |
| // (uint32tBlobVisitor))); |
| // break; |
| |
| case CcnbParser::CCN_DTAG_Timestamp: |
| NS_LOG_DEBUG ("Timestamp"); |
| if (n.m_nestedTags.size()!=1) // should be exactly one nested tag |
| throw CcnbParser::CcnbDecodingException (); |
| |
| contentObject.SetTimestamp |
| (boost::any_cast<Time> ((*n.m_nestedTags.begin())->accept |
| (timestampVisitor))); |
| break; |
| |
| // case CCN_DTAG_Type: |
| // NS_LOG_DEBUG ("Type"); |
| // if (n.m_nestedTags.size ()!=1) // should be only one nested tag |
| // throw CcnbParser::CcnbDecodingException (); |
| |
| // contentObject.GetSignedInfo ().SetContentType |
| // (static_cast<Data::ContentType> |
| // (boost::any_cast<uint32_t> ((*n.m_nestedTags.begin())->accept |
| // (contentTypeVisitor)))); |
| // break; |
| |
| case CcnbParser::CCN_DTAG_FreshnessSeconds: |
| NS_LOG_DEBUG ("FreshnessSeconds"); |
| |
| if (n.m_nestedTags.size()!=1) // should be exactly one nested tag |
| throw CcnbParser::CcnbDecodingException (); |
| |
| contentObject.SetFreshness |
| (Seconds |
| (boost::any_cast<uint32_t> ((*n.m_nestedTags.begin())->accept |
| (nonNegativeIntegerVisitor)))); |
| break; |
| |
| case CcnbParser::CCN_DTAG_KeyLocator: |
| // process nested blocks |
| BOOST_FOREACH (Ptr<CcnbParser::Block> block, n.m_nestedTags) |
| { |
| block->accept (*this, param); |
| } |
| break; |
| |
| case CcnbParser::CCN_DTAG_KeyName: |
| { |
| if (n.m_nestedTags.size ()!=1) // should be exactly one nested tag |
| throw CcnbParser::CcnbDecodingException (); |
| |
| Ptr<CcnbParser::BaseTag> nameTag = DynamicCast<CcnbParser::BaseTag>(n.m_nestedTags.front ()); |
| if (nameTag == 0) |
| throw CcnbParser::CcnbDecodingException (); |
| |
| // process name components |
| Ptr<Name> name = Create<Name> (); |
| |
| BOOST_FOREACH (Ptr<CcnbParser::Block> block, nameTag->m_nestedTags) |
| { |
| block->accept (nameVisitor, &(*name)); |
| } |
| contentObject.SetKeyLocator (name); |
| break; |
| } |
| |
| case CcnbParser::CCN_DTAG_Content: // !!! HACK |
| // This hack was necessary for memory optimizations (i.e., content is virtual payload) |
| NS_ASSERT_MSG (n.m_nestedTags.size() == 0, "Parser should have stopped just after processing <Content> tag"); |
| break; |
| |
| default: // ignore all other stuff |
| break; |
| } |
| } |
| }; |
| |
| uint32_t |
| Data::Deserialize (Buffer::Iterator start) |
| { |
| static ContentObjectVisitor contentObjectVisitor; |
| |
| Buffer::Iterator i = start; |
| Ptr<CcnbParser::Block> root = CcnbParser::Block::ParseBlock (i); |
| root->accept (contentObjectVisitor, GetPointer (m_data)); |
| |
| return i.GetDistanceFrom (start); |
| } |
| |
| void |
| Data::Print (std::ostream &os) const |
| { |
| os << "D: " << m_data->GetName (); |
| // os << "<ContentObject><Name>" << GetName () << "</Name><Content>"; |
| } |
| |
| } // ccnb |
| } // wire |
| |
| NDN_NAMESPACE_END |