blob: 86c3f5fd6f6c73e14205510302e4b364ec4aa9c3 [file] [log] [blame]
Jeff Thompsonfa306642013-06-17 15:06:57 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013, Regents of the University of California
4 * Alexander Afanasyev
5 *
6 * BSD license, See the LICENSE file for more information
7 *
8 * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
9 */
10
11#include "ccnb.h"
12#include "ndn-cpp/error.h"
13
14#include <boost/lexical_cast.hpp>
15
16namespace ndn {
17namespace wire {
18
19#define CCN_TT_BITS 3
20#define CCN_TT_MASK ((1 << CCN_TT_BITS) - 1)
21#define CCN_MAX_TINY ((1 << (7-CCN_TT_BITS)) - 1)
22#define CCN_TT_HBIT ((unsigned char)(1 << 7))
23
24void
25Ccnb::appendBlockHeader (std::ostream &os, size_t val, Ccnb::ccn_tt tt)
26{
27 unsigned char buf[1+8*((sizeof(val)+6)/7)];
28 unsigned char *p = &(buf[sizeof(buf)-1]);
29 size_t n = 1;
30 p[0] = (CCN_TT_HBIT & ~Ccnb::CCN_CLOSE_TAG) |
31 ((val & CCN_MAX_TINY) << CCN_TT_BITS) |
32 (CCN_TT_MASK & tt);
33 val >>= (7-CCN_TT_BITS);
34 while (val != 0) {
35 (--p)[0] = (((unsigned char)val) & ~CCN_TT_HBIT) | Ccnb::CCN_CLOSE_TAG;
36 n++;
37 val >>= 7;
38 }
39 os.write (reinterpret_cast<const char*> (p), n);
40 // return n;
41}
42
43void
44Ccnb::appendNumber (std::ostream &os, uint32_t number)
45{
46 std::string numberStr = boost::lexical_cast<std::string> (number);
47
48 appendBlockHeader (os, numberStr.size (), Ccnb::CCN_UDATA);
49 numberStr.size ();
50 os.write (numberStr.c_str (), numberStr.size ());
51}
52
53void
54Ccnb::appendName (std::ostream &os, const Name &name)
55{
56 Ccnb::appendBlockHeader (os, Ccnb::CCN_DTAG_Name, Ccnb::CCN_DTAG); // <Name>
57 for (Name::const_iterator component = name.begin (); component != name.end (); component ++)
58 {
59 appendTaggedBlob (os, Ccnb::CCN_DTAG_Component, component->buf (), component->size ());
60 }
61 Ccnb::appendCloser (os); // </Name>
62}
63
64void
65Ccnb::appendTimestampBlob (std::ostream &os, const TimeInterval &time)
66{
67 // CCNx method function implements some markers, which are not really defined anywhere else...
68
69 // Determine miminal number of bytes required to store the timestamp
70 int required_bytes = 2; // 12 bits for fractions of a second, 4 bits left for seconds. Sometimes it is enough
71 intmax_t ts = time.total_seconds () >> 4;
72 for (; required_bytes < 7 && ts != 0; ts >>= 8) // not more than 6 bytes?
73 required_bytes++;
74
75 appendBlockHeader(os, required_bytes, Ccnb::CCN_BLOB);
76
77 // write part with seconds
78 ts = time.total_seconds () >> 4;
79 for (int i = 0; i < required_bytes - 2; i++)
80 os.put ( ts >> (8 * (required_bytes - 3 - i)) );
81
82 /* arithmetic contortions are to avoid overflowing 31 bits */
83 ts = ((time.total_seconds () & 15) << 12) +
84 (((time.total_nanoseconds () % 1000000000) / 5 * 8 + 195312) / 390625);
85 for (int i = required_bytes - 2; i < required_bytes; i++)
86 os.put ( ts >> (8 * (required_bytes - 1 - i)) );
87
88 // return len + required_bytes;
89}
90
91void
92Ccnb::appendExclude (std::ostream &os, const Exclude &exclude)
93{
94 appendBlockHeader (os, Ccnb::CCN_DTAG_Exclude, Ccnb::CCN_DTAG); // <Exclude>
95
96 for (Exclude::const_reverse_iterator item = exclude.rbegin (); item != exclude.rend (); item ++)
97 {
98 if (!item->first.empty ())
99 appendTaggedBlob (os, Ccnb::CCN_DTAG_Component, item->first.buf (), item->first.size ());
100 if (item->second)
101 {
102 appendBlockHeader (os, Ccnb::CCN_DTAG_Any, Ccnb::CCN_DTAG); // <Any>
103 appendCloser (os); // </Any>
104 }
105 }
106 appendCloser (os); // </Exclude>
107}
108
109void
110Ccnb::appendInterest (std::ostream &os, const Interest &interest)
111{
112 Ccnb::appendBlockHeader (os, Ccnb::CCN_DTAG_Interest, Ccnb::CCN_DTAG); // <Interest>
113
114 // this is used for now as an interest template. Name should be empty
115 // Ccnb::appendName (os, interest.getName ());
116 Ccnb::appendName (os, Name ()); // <Component>...</Component>...
117
118 if (interest.getMinSuffixComponents () != Interest::ncomps)
119 {
120 appendTaggedNumber (os, Ccnb::CCN_DTAG_MinSuffixComponents, interest.getMinSuffixComponents ());
121 }
122 if (interest.getMaxSuffixComponents () != Interest::ncomps)
123 {
124 appendTaggedNumber (os, Ccnb::CCN_DTAG_MaxSuffixComponents, interest.getMaxSuffixComponents ());
125 }
126 if (interest.getExclude ().size () > 0)
127 {
128 appendExclude (os, interest.getExclude ());
129 }
130 if (interest.getChildSelector () != Interest::CHILD_DEFAULT)
131 {
132 appendTaggedNumber (os, Ccnb::CCN_DTAG_ChildSelector, interest.getChildSelector ());
133 }
134 if (interest.getAnswerOriginKind () != Interest::AOK_DEFAULT)
135 {
136 appendTaggedNumber (os, Ccnb::CCN_DTAG_AnswerOriginKind, interest.getAnswerOriginKind ());
137 }
138 if (interest.getScope () != Interest::NO_SCOPE)
139 {
140 appendTaggedNumber (os, Ccnb::CCN_DTAG_Scope, interest.getScope ());
141 }
142 if (!interest.getInterestLifetime ().is_negative ())
143 {
144 Ccnb::appendBlockHeader (os, Ccnb::CCN_DTAG_InterestLifetime, Ccnb::CCN_DTAG);
145 Ccnb::appendTimestampBlob (os, interest.getInterestLifetime ());
146 Ccnb::appendCloser (os);
147 }
148 // if (GetNonce()>0)
149 // {
150 // uint32_t nonce = interest.GetNonce();
151 // appendTaggedBlob (start, Ccnb::CCN_DTAG_Nonce, nonce);
152 // }
153
154 // if (GetNack ()>0)
155 // {
156 // appendBlockHeader (start, Ccnb::CCN_DTAG_Nack, Ccnb::CCN_DTAG);
157 // appendNumber (start, interest.GetNack ());
158 // appendCloser (start);
159 // }
160 Ccnb::appendCloser (os); // </Interest>
161}
162
163static void *SIGNATURE_Block = 0;
164static void *SINATURE_INFO_PublisherPublicKeyDigest = reinterpret_cast<void *> (1);
165static void *SINATURE_INFO_KeyLocator = reinterpret_cast<void *> (2);
166
167static const char TYPES [][3] = {
168 {0x0C, 0x04, 0xC0},
169 {0x10, 0xD0, 0x91},
170 {0x18, 0xE3, 0x44},
171 {0x28, 0x46, 0x3F},
172 {0x2C, 0x83, 0x4A},
173 {0x34, 0x00, 0x8A}
174};
175
176void
177Ccnb::appendSignature (std::ostream &os, const signature::Sha256WithRsa &signature, void *userData)
178{
179 if (userData == SIGNATURE_Block)
180 {
181 Ccnb::appendBlockHeader (os, Ccnb::CCN_DTAG_Signature, Ccnb::CCN_DTAG); // <Signature>
182 // if (signature.getDigestAlgorithm () != "2.16.840.1.101.3.4.2.1")
183 // {
184 // appendString (os, Ccnb::CCN_DTAG_DigestAlgorithm, signature.getDigestAlgorithm ());
185 // }
186 appendTaggedBlob (os, Ccnb::CCN_DTAG_SignatureBits, signature.getSignatureBits ());
187 Ccnb::appendCloser (os); // </Signature>
188 }
189 else if (userData == SINATURE_INFO_PublisherPublicKeyDigest)
190 {
191 Ccnb::appendTaggedBlob (os, Ccnb::CCN_DTAG_PublisherPublicKeyDigest, signature.getPublisherKeyDigest ());
192 }
193 else if (userData == SINATURE_INFO_KeyLocator)
194 {
195 Ccnb::appendBlockHeader (os, Ccnb::CCN_DTAG_Signature, Ccnb::CCN_DTAG); // <Signature>
196 switch (signature.getKeyLocator ().getType ())
197 {
198 case KeyLocator::NOTSET:
199 break;
200 case KeyLocator::KEY:
201 Ccnb::appendTaggedBlob (os, Ccnb::CCN_DTAG_Key, signature.getKeyLocator ().getKey ());
202 break;
203 case KeyLocator::CERTIFICATE:
204 Ccnb::appendTaggedBlob (os, Ccnb::CCN_DTAG_Key, signature.getKeyLocator ().getCertificate ());
205 break;
206 case KeyLocator::KEYNAME:
207 Ccnb::appendBlockHeader (os, Ccnb::CCN_DTAG_KeyName, Ccnb::CCN_DTAG); // <KeyName>
208 Ccnb::appendName (os, signature.getKeyLocator ().getKeyName ());
209 Ccnb::appendCloser (os); // </KeyName>
210 break;
211 }
212 Ccnb::appendCloser (os); // </Signature>
213 }
214 // other cases should not be possible, but don't do anything
215}
216
217void
218Ccnb::appendData (std::ostream &os, const Data &data)
219{
220 if (!data.getSignature ())
221 BOOST_THROW_EXCEPTION (error::wire::Ccnb ()
222 << error::msg ("Signature is required, but not set"));
223
224 Ccnb::appendBlockHeader (os, Ccnb::CCN_DTAG_ContentObject, Ccnb::CCN_DTAG); // <ContentObject>
225
226 // necessary for now, because of the changed storage order
227 data.getSignature ()->doubleDispatch (os, *this, SIGNATURE_Block);
228
229 Ccnb::appendName (os, data.getName ());
230
231 Ccnb::appendBlockHeader (os, Ccnb::CCN_DTAG_SignedInfo, Ccnb::CCN_DTAG); // <SignedInfo>
232 data.getSignature ()->doubleDispatch (os, *this, SINATURE_INFO_PublisherPublicKeyDigest);
233
234 Ccnb::appendTimestampBlob (os, data.getContent ().getTimestamp ());
235
236 BOOST_ASSERT (sizeof (TYPES) == 3 * (static_cast<int> (Content::NACK)+1));
237 Ccnb::appendTaggedBlob (os, Ccnb::CCN_DTAG_Type, TYPES [data.getContent ().getType ()], 3);
238
239 if (data.getContent ().getFreshness () != Content::noFreshness)
240 {
241 Ccnb::appendTaggedNumber (os, Ccnb::CCN_DTAG_FreshnessSeconds,
242 data.getContent ().getFreshness ().total_seconds ());
243 }
244
245 if (data.getContent ().getFinalBlockId () != Content::noFinalBlock)
246 {
247 Ccnb::appendTaggedBlob (os, Ccnb::CCN_DTAG_FinalBlockID, data.getContent ().getFinalBlockId ());
248 }
249
250 data.getSignature ()->doubleDispatch (os, *this, SINATURE_INFO_KeyLocator);
251 Ccnb::appendCloser (os); // </SignedInfo>
252
253 Ccnb::appendTaggedBlob (os, Ccnb::CCN_DTAG_Content, data.content ());
254
255 Ccnb::appendCloser (os); // </ContentObject>
256}
257
258} // namespace wire
259} // namespace ndn