blob: 0dabb66357a0f1ca599596615f7c936b51b5d87c [file] [log] [blame]
Alexander Afanasyev834f35c2011-08-16 17:13:50 -07001/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2011 University of California, Los Angeles
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author:
19 */
20
21#include "ccnx-decoding-helper.h"
22
23#include "ns3/ccnx.h"
24#include "ns3/name-components.h"
25#include "ns3/ccnx-interest-header.h"
26#include "ns3/ccnx-content-object-header.h"
27
28#include <sstream>
29#include <boost/foreach.hpp>
30
31namespace ns3 {
32
33CcnxParser::InterestVisitor CcnxDecodingHelper::m_interestVisitor;
34CcnxParser::ContentObjectVisitor CcnxDecodingHelper::m_contentObjectVisitor;
35
36size_t
37CcnxDecodingHelper::Deserialize (Buffer::Iterator start, const CcnxInterestHeader &interest)
38{
39 Buffer::Iterator i = start;
40 Ptr<CcnxParser::Block> root = CcnxParser::Block::ParseBlock (i);
41 root->accept (m_interestVisitor, interest);
42
43 return i.GetDistanceFrom (start);
44}
45
46size_t
47CcnxDecodingHelper::Deserialize (Buffer::Iterator start, const CcnxContentObjectHeader &contentObject)
48{
49 Buffer::Iterator i = start;
50 Ptr<CcnxParser::Block> root = CcnxParser::Block::ParseBlock (i);
51 root->accept (m_contentObjectVisitor, contentObject);
52
53 return i.GetDistanceFrom (start);
54}
55
56
57//////////////////////////////////////////////////////////////////////
58
59const uint8_t CCN_TT_BITS = 3;
60const uint8_t CCN_TT_MASK = ((1 << CCN_TT_BITS) - 1);
61const uint8_t CCN_MAX_TINY= ((1 << (7-CCN_TT_BITS)) - 1);
62const uint8_t CCN_TT_HBIT = ((uint8_t)(1 << 7));
63
64namespace CcnxParser {
65
66Ptr<Block> Block::ParseBlock (Buffer::Iterator &start)
67{
68 uint32_t value = 0;
69
70 // We will have problems if length field is more than 32 bits. Though it's really impossible
71 uint8_t byte = 0;
72 while (!(byte & CCN_TT_HBIT))
73 {
74 value <<= 8;
75 value += byte;
76 byte = start.ReadU8 ();
77 }
78 value <<= 4;
79 value += ( (byte&(~CCN_TT_HBIT)) >> 3);
80
81 switch (byte & CCN_TT_MASK)
82 {
83 case Ccnx::CCN_BLOB:
84 return Create<Blob> (start, value);
85 case Ccnx::CCN_UDATA:
86 return Create<Udata> (start, value);
87 case Ccnx::CCN_TAG:
88 return Create<Tag> (start, value);
89 case Ccnx::CCN_ATTR:
90 return Create<Attr> (start, value);
91 case Ccnx::CCN_DTAG:
92 return Create<Dtag> (start, value);
93 case Ccnx::CCN_DATTR:
94 return Create<Dattr> (start, value);
95 case Ccnx::CCN_EXT:
96 return Create<Ext> (start, value);
97 default:
98 throw CcnxDecodingException ();
99 }
100}
101
102Blob::Blob (Buffer::Iterator &start, uint32_t length)
103{
104 start.Read (m_blob.Begin (), length);
105}
106
107Udata::Udata (Buffer::Iterator &start, uint32_t length)
108{
109 // Ideally, the code should look like this. Unfortunately, we don't have normal compatible iterators
110 // Buffer::Iterator realStart = start;
111 // start.Next (length); // advancing forward
112 // m_udata.assign (realStart, start/*actually, it is the end*/);
113
114 m_udata.reserve (length+1); //just in case we will need \0 at the end later
115 // this is actually the way Read method is implemented in network/src/buffer.cc
116 for (uint32_t i = 0; i < length; i++)
117 {
Alexander Afanasyev7112f482011-08-17 14:05:57 -0700118 m_udata.push_back (start.ReadU8 ());
Alexander Afanasyev834f35c2011-08-16 17:13:50 -0700119 }
120}
121
122// length length in octets of UTF-8 encoding of tag name - 1 (minimum tag name length is 1)
123Tag::Tag (Buffer::Iterator &start, uint32_t length)
124{
125 m_tag.reserve (length+2); // extra byte for potential \0 at the end
126 for (uint32_t i = 0; i < (length+1); i++)
127 {
Alexander Afanasyev7112f482011-08-17 14:05:57 -0700128 m_tag.push_back (start.ReadU8 ());
Alexander Afanasyev834f35c2011-08-16 17:13:50 -0700129 }
130
131 while (!start.IsEnd () && start.PeekU8 ()!=Ccnx::CCN_CLOSE)
132 {
133 m_nestedBlocks.push_back (Block::ParseBlock (start));
134 }
135 if (start.IsEnd ())
136 throw CcnxDecodingException ();
137
138 start.ReadU8 (); // read CCN_CLOSE
139}
140
141// length length in octets of UTF-8 encoding of tag name - 1 (minimum tag name length is 1)
142Attr::Attr (Buffer::Iterator &start, uint32_t length)
143{
144 m_attr.reserve (length+2); // extra byte for potential \0 at the end
145 for (uint32_t i = 0; i < (length+1); i++)
146 {
Alexander Afanasyev7112f482011-08-17 14:05:57 -0700147 m_attr.push_back (start.ReadU8 ());
Alexander Afanasyev834f35c2011-08-16 17:13:50 -0700148 }
149 m_value = DynamicCast<Udata> (Block::ParseBlock (start));
150 if (m_value == 0)
151 throw CcnxDecodingException (); // "ATTR must be followed by UDATA field"
152}
153
154Dtag::Dtag (Buffer::Iterator &start, uint32_t dtag)
155{
156 m_dtag = dtag;
157
158 /**
159 * Hack
160 *
161 * Stop processing after encountering <Content> dtag. Actual
162 * content (including virtual payload) will be stored in Packet
163 * buffer
164 */
165 if (dtag == Ccnx::CCN_DTAG_Content)
166 return; // hack #1. Do not process nesting block for <Content>
167
168 while (!start.IsEnd () && start.PeekU8 ()!=Ccnx::CCN_CLOSE)
169 {
170 m_nestedBlocks.push_back (Block::ParseBlock (start));
171
172 // hack #2. Stop processing nested blocks if last block was <Content>
173 if (m_dtag == Ccnx::CCN_DTAG_ContentObject && // we are in <ContentObject>
174 DynamicCast<Dtag> (m_nestedBlocks.back())!=0 && // last block is DTAG
175 DynamicCast<Dtag> (m_nestedBlocks.back())->m_dtag == Ccnx::CCN_DTAG_Content)
176 {
177 return;
178 }
179 }
180 if (start.IsEnd ())
181 throw CcnxDecodingException ();
182
183 start.ReadU8 (); // read CCN_CLOSE
184}
185
186// dictionary attributes are not used (yet?) in CCNx
187Dattr::Dattr (Buffer::Iterator &start, uint32_t dattr)
188{
189 m_dattr = dattr;
190 m_value = DynamicCast<Udata> (Block::ParseBlock (start));
191 if (m_value == 0)
192 throw CcnxDecodingException (); // "ATTR must be followed by UDATA field"
193}
194
195Ext::Ext (Buffer::Iterator &start, uint32_t extSubtype)
196{
197 m_extSubtype = extSubtype;
198}
199
200void
201DepthFirstVisitor::visit (Blob &n)
202{
203 // Buffer n.m_blob;
204}
205
206void
207DepthFirstVisitor::visit (Udata &n)
208{
209 // std::string n.m_udata;
210}
211
212void
213DepthFirstVisitor::visit (Tag &n)
214{
215 // std::string n.m_tag;
216 // std::list<Ptr<Block> > n.m_nestedBlocks;
217 BOOST_FOREACH (Ptr<Block> block, n.m_nestedBlocks)
218 {
219 block->accept (*this);
220 }
221}
222
223void
224DepthFirstVisitor::visit (Attr &n)
225{
226 // std::string n.m_attr;
227 // Ptr<Udata> n.m_value;
228}
229
230void
231DepthFirstVisitor::visit (Dtag &n)
232{
233 // uint32_t n.m_dtag;
234 // std::list<Ptr<Block> > n.m_nestedBlocks;
235 BOOST_FOREACH (Ptr<Block> block, n.m_nestedBlocks)
236 {
237 block->accept (*this);
238 }
239}
240
241void
242DepthFirstVisitor::visit (Dattr &n)
243{
244 // uint32_t n.m_dattr;
245 // Ptr<Udata> n.m_value;
246}
247
248void
249DepthFirstVisitor::visit (Ext &n)
250{
251 // uint64_t n.m_extSubtype;
252}
253
254//////////////////////////////////////////////////////////////////////
255
256boost::any
257GJNoArguDepthFirstVisitor::visit (Blob &n)
258{
259 // Buffer n.m_blob;
260 return n.m_blob;
261}
262
263boost::any
264GJNoArguDepthFirstVisitor::visit (Udata &n)
265{
266 // std::string n.m_udata;
267 return n.m_udata;
268}
269
270boost::any
271GJNoArguDepthFirstVisitor::visit (Tag &n)
272{
273 // std::string n.m_tag;
274 // std::list<Ptr<Block> > n.m_nestedBlocks;
275 BOOST_FOREACH (Ptr<Block> block, n.m_nestedBlocks)
276 {
277 block->accept (*this);
278 }
279 return boost::any();
280}
281
282boost::any
283GJNoArguDepthFirstVisitor::visit (Attr &n)
284{
285 // std::string n.m_attr;
286 // Ptr<Udata> n.m_value;
287 return boost::any(
288 std::pair<std::string,std::string> (
289 n.m_attr,
290 boost::any_cast<std::string> (n.m_value->accept (*this))
291 ));
292}
293
294boost::any
295GJNoArguDepthFirstVisitor::visit (Dtag &n)
296{
297 // uint32_t n.m_dtag;
298 // std::list<Ptr<Block> > n.m_nestedBlocks;
299 BOOST_FOREACH (Ptr<Block> block, n.m_nestedBlocks)
300 {
301 block->accept (*this);
302 }
303 return boost::any();
304}
305
306boost::any
307GJNoArguDepthFirstVisitor::visit (Dattr &n)
308{
309 // uint32_t n.m_dattr;
310 // Ptr<Udata> n.m_value;
311 return boost::any(
312 std::pair<uint32_t,std::string> (
313 n.m_dattr,
314 boost::any_cast<std::string> (n.m_value->accept (*this))
315 ));
316}
317
318boost::any
319GJNoArguDepthFirstVisitor::visit (Ext &n)
320{
321 // uint64_t n.m_extSubtype;
322 return n.m_extSubtype;
323}
324
325//////////////////////////////////////////////////////////////////////
326
327void
328GJVoidDepthFirstVisitor::visit (Blob &n, boost::any param)
329{
330 // Buffer n.m_blob;
331}
332
333void
334GJVoidDepthFirstVisitor::visit (Udata &n, boost::any param)
335{
336 // std::string n.m_udata;
337}
338
339void
340GJVoidDepthFirstVisitor::visit (Tag &n, boost::any param)
341{
342 // std::string n.m_tag;
343 // std::list<Ptr<Block> > n.m_nestedBlocks;
344 BOOST_FOREACH (Ptr<Block> block, n.m_nestedBlocks)
345 {
346 block->accept (*this, param);
347 }
348}
349
350void
351GJVoidDepthFirstVisitor::visit (Attr &n, boost::any param)
352{
353 // std::string n.m_attr;
354 // Ptr<Udata> n.m_value;
355}
356
357void
358GJVoidDepthFirstVisitor::visit (Dtag &n, boost::any param)
359{
360 // uint32_t n.m_dtag;
361 // std::list<Ptr<Block> > n.m_nestedBlocks;
362 BOOST_FOREACH (Ptr<Block> block, n.m_nestedBlocks)
363 {
364 block->accept (*this, param);
365 }
366}
367
368void
369GJVoidDepthFirstVisitor::visit (Dattr &n, boost::any param)
370{
371 // uint32_t n.m_dattr;
372 // Ptr<Udata> n.m_value;
373}
374
375void
376GJVoidDepthFirstVisitor::visit (Ext &n, boost::any param)
377{
378 // uint64_t n.m_extSubtype;
379}
380
381//////////////////////////////////////////////////////////////////////
382
383boost::any
384GJDepthFirstVisitor::visit (Blob &n, boost::any param)
385{
386 // Buffer n.m_blob;
387 return n.m_blob;
388}
389
390boost::any
391GJDepthFirstVisitor::visit (Udata &n, boost::any param)
392{
393 // std::string n.m_udata;
394 return n.m_udata;
395}
396
397boost::any
398GJDepthFirstVisitor::visit (Tag &n, boost::any param)
399{
400 // std::string n.m_tag;
401 // std::list<Ptr<Block> > n.m_nestedBlocks;
402 BOOST_FOREACH (Ptr<Block> block, n.m_nestedBlocks)
403 {
404 block->accept (*this, param);
405 }
406 return boost::any();
407}
408
409boost::any
410GJDepthFirstVisitor::visit (Attr &n, boost::any param)
411{
412 // std::string n.m_attr;
413 // Ptr<Udata> n.m_value;
414 return boost::any(
415 std::pair<std::string,std::string> (
416 n.m_attr,
417 boost::any_cast<std::string> (n.m_value->accept (*this,param))
418 ));
419}
420
421boost::any
422GJDepthFirstVisitor::visit (Dtag &n, boost::any param)
423{
424 // uint32_t n.m_dtag;
425 // std::list<Ptr<Block> > n.m_nestedBlocks;
426 BOOST_FOREACH (Ptr<Block> block, n.m_nestedBlocks)
427 {
428 block->accept (*this, param);
429 }
430 return boost::any();
431}
432
433boost::any
434GJDepthFirstVisitor::visit (Dattr &n, boost::any param)
435{
436 // uint32_t n.m_dattr;
437 // Ptr<Udata> n.m_value;
438 return boost::any(
439 std::pair<uint32_t,std::string> (
440 n.m_dattr,
441 boost::any_cast<std::string> (n.m_value->accept (*this,param))
442 ));
443}
444
445boost::any
446GJDepthFirstVisitor::visit (Ext &n, boost::any param)
447{
448 // uint64_t n.m_extSubtype;
449 return n.m_extSubtype;
450}
451
452//////////////////////////////////////////////////////////////////////
453
454boost::any
455NonNegativeIntegerVisitor::visit (Blob &n) //to throw parsing error
456{
457 // Buffer n.m_blob;
458 throw CcnxDecodingException ();
459}
460
461boost::any
462NonNegativeIntegerVisitor::visit (Udata &n)
463{
464 // std::string n.m_udata;
465 std::istringstream is (n.m_udata);
466 int32_t value;
467 is >> value;
468 if (value<0) // value should be non-negative
469 throw CcnxDecodingException ();
470
471 return static_cast<uint32_t> (value);
472}
473
474
475//////////////////////////////////////////////////////////////////////
476
477boost::any
478StringVisitor::visit (Blob &n) //to throw parsing error
479{
480 // Buffer n.m_blob;
481 throw CcnxDecodingException ();
482}
483
484boost::any
485StringVisitor::visit (Udata &n)
486{
487 // std::string n.m_udata;
488 return n.m_udata;
489}
490
491//////////////////////////////////////////////////////////////////////
492
493StringVisitor NameComponentsVisitor::m_stringVisitor;
494
495void
496NameComponentsVisitor::visit (Dtag &n, boost::any param/*should be Name::Components&*/)
497{
498 // uint32_t n.m_dtag;
499 // std::list<Ptr<Block> > n.m_nestedBlocks;
500 Name::Components &components = boost::any_cast<Name::Components&> (param);
501
502 switch (n.m_dtag)
503 {
504 case Ccnx::CCN_DTAG_Component:
505 if (n.m_nestedBlocks.size()!=1) // should be exactly one UDATA inside this tag
506 throw CcnxDecodingException ();
507 components.Add (
508 boost::any_cast<std::string> ((*n.m_nestedBlocks.begin())->accept(
509 m_stringVisitor
510 )));
511 break;
512 default:
513 // ignore any other components
514 // when parsing Exclude, there could be <Any /> and <Bloom /> tags
515 break;
516 }
517}
518
519//////////////////////////////////////////////////////////////////////
520
521NonNegativeIntegerVisitor InterestVisitor::m_nonNegativeIntegerVisitor;
522NameComponentsVisitor InterestVisitor::m_nameComponentsVisitor;
523
524// We don't really care about any other fields
525void
526InterestVisitor::visit (Dtag &n, boost::any param/*should be CcnxInterestHeader&*/)
527{
528 // uint32_t n.m_dtag;
529 // std::list<Ptr<Block> > n.m_nestedBlocks;
530 CcnxInterestHeader &interest = boost::any_cast<CcnxInterestHeader&> (param);
531
532 switch (n.m_dtag)
533 {
534 case Ccnx::CCN_DTAG_Interest:
535 // process nested blocks
536 BOOST_FOREACH (Ptr<Block> block, n.m_nestedBlocks)
537 {
538 block->accept (*this, param);
539 }
540 break;
541 case Ccnx::CCN_DTAG_Name:
542 {
543 // process name components
544 Ptr<Name::Components> name = Create<Name::Components> ();
545
546 BOOST_FOREACH (Ptr<Block> block, n.m_nestedBlocks)
547 {
548 block->accept (m_nameComponentsVisitor, *name);
549 }
550 interest.SetName (name);
551 break;
552 }
553 case Ccnx::CCN_DTAG_MinSuffixComponents:
554 if (n.m_nestedBlocks.size()!=1) // should be exactly one UDATA inside this tag
555 throw CcnxDecodingException ();
556 interest.SetMinSuffixComponents (
557 boost::any_cast<uint32_t> (
558 (*n.m_nestedBlocks.begin())->accept(
559 m_nonNegativeIntegerVisitor
560 )));
561 break;
562 case Ccnx::CCN_DTAG_MaxSuffixComponents:
563 if (n.m_nestedBlocks.size()!=1) // should be exactly one UDATA inside this tag
564 throw CcnxDecodingException ();
565 interest.SetMaxSuffixComponents (
566 boost::any_cast<uint32_t> (
567 (*n.m_nestedBlocks.begin())->accept(
568 m_nonNegativeIntegerVisitor
569 )));
570 break;
571 case Ccnx::CCN_DTAG_Exclude:
572 {
573 // process exclude components
574 Ptr<Name::Components> exclude = Create<Name::Components> ();
575
576 BOOST_FOREACH (Ptr<Block> block, n.m_nestedBlocks)
577 {
578 block->accept (m_nameComponentsVisitor, *exclude);
579 }
580 interest.SetExclude (exclude);
581 break;
582 }
583 case Ccnx::CCN_DTAG_ChildSelector:
584 if (n.m_nestedBlocks.size()!=1) // should be exactly one UDATA inside this tag
585 throw CcnxDecodingException ();
586
587 interest.SetChildSelector (
588 1 == boost::any_cast<uint32_t> (
589 (*n.m_nestedBlocks.begin())->accept(
590 m_nonNegativeIntegerVisitor
591 )));
592 break;
593 case Ccnx::CCN_DTAG_AnswerOriginKind:
594 if (n.m_nestedBlocks.size()!=1) // should be exactly one UDATA inside this tag
595 throw CcnxDecodingException ();
596 interest.SetAnswerOriginKind (
597 1 == boost::any_cast<uint32_t> (
598 (*n.m_nestedBlocks.begin())->accept(
599 m_nonNegativeIntegerVisitor
600 )));
601 break;
602 case Ccnx::CCN_DTAG_Scope:
603 if (n.m_nestedBlocks.size()!=1) // should be exactly one UDATA inside this tag
604 throw CcnxDecodingException ();
605 interest.SetScope (
606 boost::any_cast<uint32_t> (
607 (*n.m_nestedBlocks.begin())->accept(
608 m_nonNegativeIntegerVisitor
609 )));
610 break;
611 case Ccnx::CCN_DTAG_InterestLifetime:
612 if (n.m_nestedBlocks.size()!=1) // should be exactly one UDATA inside this tag
613 throw CcnxDecodingException ();
614 break;
615 case Ccnx::CCN_DTAG_Nonce:
616 if (n.m_nestedBlocks.size()!=1) // should be exactly one UDATA inside this tag
617 throw CcnxDecodingException ();
618 break;
619 }
620}
621
622//////////////////////////////////////////////////////////////////////
623
624NameComponentsVisitor ContentObjectVisitor::m_nameComponentsVisitor;
625
626// We don't really care about any other fields
627void
628ContentObjectVisitor::visit (Dtag &n, boost::any param/*should be CcnxContentObjectHeader&*/)
629{
630 // uint32_t n.m_dtag;
631 // std::list<Ptr<Block> > n.m_nestedBlocks;
632 CcnxContentObjectHeader &contentObject = boost::any_cast<CcnxContentObjectHeader&> (param);
633
634 switch (n.m_dtag)
635 {
636 case Ccnx::CCN_DTAG_ContentObject:
637 // process nested blocks
638 BOOST_FOREACH (Ptr<Block> block, n.m_nestedBlocks)
639 {
640 block->accept (*this, param);
641 }
642 break;
643 case Ccnx::CCN_DTAG_Name:
644 {
645 // process name components
646 Ptr<Name::Components> name = Create<Name::Components> ();
647
648 BOOST_FOREACH (Ptr<Block> block, n.m_nestedBlocks)
649 {
650 block->accept (m_nameComponentsVisitor, *name);
651 }
652 contentObject.SetName (name);
653 break;
654 }
655 case Ccnx::CCN_DTAG_Signature: // ignoring
656 break;
657 case Ccnx::CCN_DTAG_SignedInfo: // ignoring
658 break;
659 case Ccnx::CCN_DTAG_Content: // !!! HACK
660 // This hack was necessary for memory optimizations (i.e., content is virtual payload)
661 NS_ASSERT_MSG (n.m_nestedBlocks.size() == 0, "Parser should have stopped just after processing <Content> tag");
662 break;
663 }
664}
665
666} // namespace CcnxParser
667} // namespace ns3