blob: 5f8d6673ffffb1904f412bb1aaa0fde491583e96 [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
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080050 LocalControlHeader()
51 : m_incomingFaceId(INVALID_FACE_ID)
52 , m_nextHopFaceId(INVALID_FACE_ID)
53 {
54 }
55
56 /**
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070057 * @brief Create from wire encoding
58 *
59 * @sa wireDecode
60 */
61 explicit
62 LocalControlHeader(const Block& wire,
63 bool encodeIncomingFaceId = true, bool encodeNextHopFaceId = true)
64 {
65 wireDecode(wire, encodeIncomingFaceId, encodeNextHopFaceId);
66 }
67
68 /**
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080069 * @brief Create wire encoding with options LocalControlHeader and the supplied item
70 *
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080071 * The caller is responsible of checking whether LocalControlHeader contains
72 * any information.
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080073 *
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080074 * !It is an error to call this method if neither IncomingFaceId nor NextHopFaceId is
75 * set, or neither of them is enabled.
76 *
77 * @throws LocalControlHeader::Error when empty LocalControlHeader be produced
78 *
79 * @returns Block, containing LocalControlHeader. Top-level length field of the
80 * returned LocalControlHeader includes payload length, but the memory
81 * block is independent of the payload's wire buffer. It is expected
82 * that both LocalControlHeader's and payload's wire will be send out
83 * together within a single send call.
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080084 *
85 * @see http://redmine.named-data.net/projects/nfd/wiki/LocalControlHeader
86 */
87 template<class U>
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080088 inline Block
89 wireEncode(const U& payload,
90 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070091
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080092 /**
93 * @brief Decode from the wire format and set LocalControlHeader on the supplied item
94 *
95 * The supplied wire MUST contain LocalControlHeader. Determination whether the optional
96 * LocalControlHeader should be done before calling this method.
97 */
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070098 inline void
Alexander Afanasyev37bb1902014-02-19 23:57:23 -080099 wireDecode(const Block& wire,
100 bool encodeIncomingFaceId = true, bool encodeNextHopFaceId = true);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800101
102 inline static const Block&
103 getPayload(const Block& wire);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700104
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800105 ///////////////////////////////////////////////////////////////////////////////
106 ///////////////////////////////////////////////////////////////////////////////
107 ///////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800108 // Getters/setters
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800109
110 bool
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800111 empty(bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800112 {
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800113 return !((encodeIncomingFaceId && hasIncomingFaceId()) ||
114 (encodeNextHopFaceId && hasNextHopFaceId()));
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800115 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700116
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800117 //
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700118
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800119 bool
120 hasIncomingFaceId() const
121 {
122 return m_incomingFaceId != INVALID_FACE_ID;
123 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700124
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800125 uint64_t
126 getIncomingFaceId() const
127 {
128 return m_incomingFaceId;
129 }
130
131 void
132 setIncomingFaceId(uint64_t incomingFaceId)
133 {
134 m_incomingFaceId = incomingFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800135 }
136
137 //
138
139 bool
140 hasNextHopFaceId() const
141 {
142 return m_nextHopFaceId != INVALID_FACE_ID;
143 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700144
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800145 uint64_t
146 getNextHopFaceId() const
147 {
148 return m_nextHopFaceId;
149 }
150
151 void
152 setNextHopFaceId(uint64_t nextHopFaceId)
153 {
154 m_nextHopFaceId = nextHopFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800155 }
156
157private:
Alexander Afanasyev74633892015-02-08 18:08:46 -0800158 template<encoding::Tag TAG>
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800159 inline size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800160 wireEncode(EncodingImpl<TAG>& block, size_t payloadSize,
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800161 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700162
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800163private:
164 uint64_t m_incomingFaceId;
165 uint64_t m_nextHopFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800166};
167
168
169/**
170 * @brief Fast encoding or block size estimation
171 */
Alexander Afanasyev74633892015-02-08 18:08:46 -0800172template<encoding::Tag TAG>
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800173inline size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800174LocalControlHeader::wireEncode(EncodingImpl<TAG>& block, size_t payloadSize,
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800175 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800176{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700177 size_t totalLength = payloadSize;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800178
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800179 if (encodeIncomingFaceId && hasIncomingFaceId())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800180 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700181 totalLength += prependNonNegativeIntegerBlock(block,
182 tlv::nfd::IncomingFaceId, getIncomingFaceId());
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800183 }
184
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800185 if (encodeNextHopFaceId && hasNextHopFaceId())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800186 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700187 totalLength += prependNonNegativeIntegerBlock(block,
188 tlv::nfd::NextHopFaceId, getNextHopFaceId());
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800189 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700190
191 totalLength += block.prependVarNumber(totalLength);
192 totalLength += block.prependVarNumber(tlv::nfd::LocalControlHeader);
193 return totalLength;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800194}
195
196template<class U>
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800197inline Block
198LocalControlHeader::wireEncode(const U& payload,
199 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800200{
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800201 /// @todo should this be BOOST_ASSERT instead? This is kind of unnecessary overhead
202 if (empty(encodeIncomingFaceId, encodeNextHopFaceId))
203 throw Error("Requested wire for LocalControlHeader, but none of the fields are set or enabled");
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800204
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800205 EncodingEstimator estimator;
206 size_t length = wireEncode(estimator, payload.wireEncode().size(),
207 encodeIncomingFaceId, encodeNextHopFaceId);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700208
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800209 EncodingBuffer buffer(length);
210 wireEncode(buffer, payload.wireEncode().size(),
211 encodeIncomingFaceId, encodeNextHopFaceId);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800212
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800213 return buffer.block(false);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800214}
215
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700216inline void
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800217LocalControlHeader::wireDecode(const Block& wire,
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700218 bool encodeIncomingFaceId/* = true*/,
219 bool encodeNextHopFaceId/* = true*/)
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800220{
221 BOOST_ASSERT(wire.type() == tlv::nfd::LocalControlHeader);
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800222 wire.parse();
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800223
224 m_incomingFaceId = INVALID_FACE_ID;
225 m_nextHopFaceId = INVALID_FACE_ID;
226
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800227 for (Block::element_const_iterator i = wire.elements_begin();
228 i != wire.elements_end();
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800229 ++i)
230 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700231 switch (i->type())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800232 {
233 case tlv::nfd::IncomingFaceId:
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800234 if (encodeIncomingFaceId)
235 m_incomingFaceId = readNonNegativeInteger(*i);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800236 break;
237 case tlv::nfd::NextHopFaceId:
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800238 if (encodeNextHopFaceId)
239 m_nextHopFaceId = readNonNegativeInteger(*i);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800240 break;
241 default:
242 // ignore all unsupported
243 break;
244 }
245 }
246}
247
248inline const Block&
249LocalControlHeader::getPayload(const Block& wire)
250{
251 if (wire.type() == tlv::nfd::LocalControlHeader)
252 {
253 wire.parse();
254 if (wire.elements_size() < 1)
255 return wire; // don't throw an error, but don't continue processing
256
257 return wire.elements()[wire.elements().size()-1];
258 }
259 else
260 {
261 return wire;
262 }
263}
264
265
266} // namespace nfd
267} // namespace ndn
268
269#endif // NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP