blob: 8108230ab0de46b5f8f29359b9f64eef7779cd57 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -08002/**
Alexander Afanasyev74633892015-02-08 18:08:46 -08003 * Copyright (c) 2013-2015 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080020 */
21
22#ifndef NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP
23#define NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP
24
25#include "../encoding/encoding-buffer.hpp"
26#include "../encoding/tlv-nfd.hpp"
Alexander Afanasyev01065fb2014-10-02 13:01:46 -070027#include "../encoding/block-helpers.hpp"
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080028
29namespace ndn {
30namespace nfd {
31
Alexander Afanasyev4671bf72014-05-19 09:01:37 -040032/**
33 * @ingroup management
34 * @brief Class to handle work with LocalControlHeader
35 * @sa http://redmine.named-data.net/projects/nfd/wiki/LocalControlHeader
36 */
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080037class LocalControlHeader
38{
39public:
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070040 class Error : public std::runtime_error
41 {
42 public:
43 explicit
44 Error(const std::string& what)
45 : std::runtime_error(what)
46 {
47 }
48 };
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080049
Jiewen Tanc759a202015-01-29 23:31:09 -080050 enum EncodeFlags : uint8_t {
51 ENCODE_NONE = 0,
52 ENCODE_INCOMING_FACE_ID = (1 << 0),
53 ENCODE_NEXT_HOP = (1 << 1),
54 ENCODE_CACHING_POLICY = (1 << 2),
55 ENCODE_ALL = 0xff
56 };
57
58 enum CachingPolicy : uint8_t {
59 INVALID_POLICY = 0,
60 NO_CACHE = 1
61 };
62
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080063 LocalControlHeader()
64 : m_incomingFaceId(INVALID_FACE_ID)
65 , m_nextHopFaceId(INVALID_FACE_ID)
Jiewen Tanc759a202015-01-29 23:31:09 -080066 , m_cachingPolicy(CachingPolicy::INVALID_POLICY)
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080067 {
68 }
69
70 /**
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070071 * @brief Create from wire encoding
72 *
73 * @sa wireDecode
74 */
75 explicit
Jiewen Tanc759a202015-01-29 23:31:09 -080076 LocalControlHeader(const Block& wire, uint8_t encodeMask = ENCODE_ALL)
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070077 {
Jiewen Tanc759a202015-01-29 23:31:09 -080078 wireDecode(wire, encodeMask);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070079 }
80
81 /**
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080082 * @brief Create wire encoding with options LocalControlHeader and the supplied item
83 *
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080084 * The caller is responsible of checking whether LocalControlHeader contains
85 * any information.
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080086 *
Jiewen Tanc759a202015-01-29 23:31:09 -080087 * !It is an error to call this method if none of IncomingFaceId, NextHopFaceId and CachingPolicy
88 * are set, or neither of them are enabled.
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080089 *
90 * @throws LocalControlHeader::Error when empty LocalControlHeader be produced
91 *
92 * @returns Block, containing LocalControlHeader. Top-level length field of the
93 * returned LocalControlHeader includes payload length, but the memory
94 * block is independent of the payload's wire buffer. It is expected
95 * that both LocalControlHeader's and payload's wire will be send out
96 * together within a single send call.
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080097 *
98 * @see http://redmine.named-data.net/projects/nfd/wiki/LocalControlHeader
99 */
100 template<class U>
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800101 inline Block
Jiewen Tanc759a202015-01-29 23:31:09 -0800102 wireEncode(const U& payload, uint8_t encodeMask = ENCODE_ALL) const;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700103
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800104 /**
105 * @brief Decode from the wire format and set LocalControlHeader on the supplied item
106 *
107 * The supplied wire MUST contain LocalControlHeader. Determination whether the optional
108 * LocalControlHeader should be done before calling this method.
109 */
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700110 inline void
Jiewen Tanc759a202015-01-29 23:31:09 -0800111 wireDecode(const Block& wire, uint8_t encodeMask = ENCODE_ALL);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800112
113 inline static const Block&
114 getPayload(const Block& wire);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700115
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800116 ///////////////////////////////////////////////////////////////////////////////
117 ///////////////////////////////////////////////////////////////////////////////
118 ///////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800119 // Getters/setters
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800120
121 bool
Jiewen Tanc759a202015-01-29 23:31:09 -0800122 empty(uint8_t encodeMask) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800123 {
Jiewen Tanc759a202015-01-29 23:31:09 -0800124 bool needIncomingFaceId = encodeMask & ENCODE_INCOMING_FACE_ID;
125 bool needNextHopFaceId = encodeMask & ENCODE_NEXT_HOP;
126 bool needCachingPolicy = encodeMask & ENCODE_CACHING_POLICY;
127
128 return !((needIncomingFaceId && hasIncomingFaceId()) ||
129 (needNextHopFaceId && hasNextHopFaceId()) ||
130 (needCachingPolicy && hasCachingPolicy()));
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800131 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700132
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800133 //
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700134
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800135 bool
136 hasIncomingFaceId() const
137 {
138 return m_incomingFaceId != INVALID_FACE_ID;
139 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700140
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800141 uint64_t
142 getIncomingFaceId() const
143 {
144 return m_incomingFaceId;
145 }
146
147 void
148 setIncomingFaceId(uint64_t incomingFaceId)
149 {
150 m_incomingFaceId = incomingFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800151 }
152
153 //
154
155 bool
156 hasNextHopFaceId() const
157 {
158 return m_nextHopFaceId != INVALID_FACE_ID;
159 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700160
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800161 uint64_t
162 getNextHopFaceId() const
163 {
164 return m_nextHopFaceId;
165 }
166
167 void
168 setNextHopFaceId(uint64_t nextHopFaceId)
169 {
170 m_nextHopFaceId = nextHopFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800171 }
172
Jiewen Tanc759a202015-01-29 23:31:09 -0800173 //
174
175 bool
176 hasCachingPolicy() const
177 {
178 return m_cachingPolicy != CachingPolicy::INVALID_POLICY;
179 }
180
181 CachingPolicy
182 getCachingPolicy() const
183 {
184 return m_cachingPolicy;
185 }
186
187 void
188 setCachingPolicy(CachingPolicy cachingPolicy)
189 {
190 m_cachingPolicy = cachingPolicy;
191 }
192
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800193private:
Alexander Afanasyev74633892015-02-08 18:08:46 -0800194 template<encoding::Tag TAG>
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800195 inline size_t
Jiewen Tanc759a202015-01-29 23:31:09 -0800196 wireEncode(EncodingImpl<TAG>& block, size_t payloadSize, uint8_t encodeMask) const;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700197
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800198private:
199 uint64_t m_incomingFaceId;
200 uint64_t m_nextHopFaceId;
Jiewen Tanc759a202015-01-29 23:31:09 -0800201 CachingPolicy m_cachingPolicy;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800202};
203
204
205/**
206 * @brief Fast encoding or block size estimation
207 */
Alexander Afanasyev74633892015-02-08 18:08:46 -0800208template<encoding::Tag TAG>
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800209inline size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800210LocalControlHeader::wireEncode(EncodingImpl<TAG>& block, size_t payloadSize,
Jiewen Tanc759a202015-01-29 23:31:09 -0800211 uint8_t encodeMask) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800212{
Jiewen Tanc759a202015-01-29 23:31:09 -0800213 bool needIncomingFaceId = encodeMask & ENCODE_INCOMING_FACE_ID;
214 bool needNextHopFaceId = encodeMask & ENCODE_NEXT_HOP;
215 bool needCachingPolicy = encodeMask & ENCODE_CACHING_POLICY;
216
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700217 size_t totalLength = payloadSize;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800218
Jiewen Tanc759a202015-01-29 23:31:09 -0800219 if (needIncomingFaceId && hasIncomingFaceId())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800220 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700221 totalLength += prependNonNegativeIntegerBlock(block,
222 tlv::nfd::IncomingFaceId, getIncomingFaceId());
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800223 }
224
Jiewen Tanc759a202015-01-29 23:31:09 -0800225 if (needNextHopFaceId && hasNextHopFaceId())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800226 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700227 totalLength += prependNonNegativeIntegerBlock(block,
228 tlv::nfd::NextHopFaceId, getNextHopFaceId());
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800229 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700230
Jiewen Tanc759a202015-01-29 23:31:09 -0800231 if (needCachingPolicy && hasCachingPolicy())
232 {
233 size_t cachingPolicyLength = 0;
234 cachingPolicyLength += block.prependVarNumber(0);
235 cachingPolicyLength += block.prependVarNumber(tlv::nfd::NoCache);
236 cachingPolicyLength += block.prependVarNumber(cachingPolicyLength);
237 cachingPolicyLength += block.prependVarNumber(tlv::nfd::CachingPolicy);
238
239 totalLength += cachingPolicyLength;
240 }
241
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700242 totalLength += block.prependVarNumber(totalLength);
243 totalLength += block.prependVarNumber(tlv::nfd::LocalControlHeader);
244 return totalLength;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800245}
246
247template<class U>
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800248inline Block
Jiewen Tanc759a202015-01-29 23:31:09 -0800249LocalControlHeader::wireEncode(const U& payload, uint8_t encodeMask) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800250{
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800251 /// @todo should this be BOOST_ASSERT instead? This is kind of unnecessary overhead
Jiewen Tanc759a202015-01-29 23:31:09 -0800252 if (empty(encodeMask))
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800253 throw Error("Requested wire for LocalControlHeader, but none of the fields are set or enabled");
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800254
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800255 EncodingEstimator estimator;
Jiewen Tanc759a202015-01-29 23:31:09 -0800256 size_t length = wireEncode(estimator, payload.wireEncode().size(), encodeMask);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700257
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800258 EncodingBuffer buffer(length);
Jiewen Tanc759a202015-01-29 23:31:09 -0800259 wireEncode(buffer, payload.wireEncode().size(), encodeMask);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800260
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800261 return buffer.block(false);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800262}
263
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700264inline void
Jiewen Tanc759a202015-01-29 23:31:09 -0800265LocalControlHeader::wireDecode(const Block& wire, uint8_t encodeMask)
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800266{
Jiewen Tanc759a202015-01-29 23:31:09 -0800267 bool needIncomingFaceId = encodeMask & ENCODE_INCOMING_FACE_ID;
268 bool needNextHopFaceId = encodeMask & ENCODE_NEXT_HOP;
269 bool needCachingPolicy = encodeMask & ENCODE_CACHING_POLICY;
270
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800271 BOOST_ASSERT(wire.type() == tlv::nfd::LocalControlHeader);
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800272 wire.parse();
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800273
274 m_incomingFaceId = INVALID_FACE_ID;
275 m_nextHopFaceId = INVALID_FACE_ID;
Jiewen Tanc759a202015-01-29 23:31:09 -0800276 m_cachingPolicy = CachingPolicy::INVALID_POLICY;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800277
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800278 for (Block::element_const_iterator i = wire.elements_begin();
279 i != wire.elements_end();
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800280 ++i)
281 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700282 switch (i->type())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800283 {
284 case tlv::nfd::IncomingFaceId:
Jiewen Tanc759a202015-01-29 23:31:09 -0800285 if (needIncomingFaceId)
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800286 m_incomingFaceId = readNonNegativeInteger(*i);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800287 break;
288 case tlv::nfd::NextHopFaceId:
Jiewen Tanc759a202015-01-29 23:31:09 -0800289 if (needNextHopFaceId)
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800290 m_nextHopFaceId = readNonNegativeInteger(*i);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800291 break;
Jiewen Tanc759a202015-01-29 23:31:09 -0800292 case tlv::nfd::CachingPolicy:
293 if (needCachingPolicy) {
294 i->parse();
295 Block::element_const_iterator it = i->elements_begin();
296 if (it != i->elements_end() && it->type() == tlv::nfd::NoCache) {
297 m_cachingPolicy = CachingPolicy::NO_CACHE;
298 }
299 else {
300 throw Error("CachingPolicy: Missing required NoCache field");
301 }
302 }
303 break;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800304 default:
305 // ignore all unsupported
306 break;
307 }
308 }
309}
310
311inline const Block&
312LocalControlHeader::getPayload(const Block& wire)
313{
314 if (wire.type() == tlv::nfd::LocalControlHeader)
315 {
316 wire.parse();
317 if (wire.elements_size() < 1)
318 return wire; // don't throw an error, but don't continue processing
319
320 return wire.elements()[wire.elements().size()-1];
321 }
322 else
323 {
324 return wire;
325 }
326}
327
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800328} // namespace nfd
329} // namespace ndn
330
331#endif // NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP