blob: 71509ba29afba74e0229f0506a2f31ca13f829ba [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 Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 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"
27
28namespace ndn {
29namespace nfd {
30
Alexander Afanasyev4671bf72014-05-19 09:01:37 -040031/**
32 * @ingroup management
33 * @brief Class to handle work with LocalControlHeader
34 * @sa http://redmine.named-data.net/projects/nfd/wiki/LocalControlHeader
35 */
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080036class LocalControlHeader
37{
38public:
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070039 class Error : public std::runtime_error
40 {
41 public:
42 explicit
43 Error(const std::string& what)
44 : std::runtime_error(what)
45 {
46 }
47 };
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080048
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080049 LocalControlHeader()
50 : m_incomingFaceId(INVALID_FACE_ID)
51 , m_nextHopFaceId(INVALID_FACE_ID)
52 {
53 }
54
55 /**
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070056 * @brief Create from wire encoding
57 *
58 * @sa wireDecode
59 */
60 explicit
61 LocalControlHeader(const Block& wire,
62 bool encodeIncomingFaceId = true, bool encodeNextHopFaceId = true)
63 {
64 wireDecode(wire, encodeIncomingFaceId, encodeNextHopFaceId);
65 }
66
67 /**
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080068 * @brief Create wire encoding with options LocalControlHeader and the supplied item
69 *
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080070 * The caller is responsible of checking whether LocalControlHeader contains
71 * any information.
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080072 *
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080073 * !It is an error to call this method if neither IncomingFaceId nor NextHopFaceId is
74 * set, or neither of them is enabled.
75 *
76 * @throws LocalControlHeader::Error when empty LocalControlHeader be produced
77 *
78 * @returns Block, containing LocalControlHeader. Top-level length field of the
79 * returned LocalControlHeader includes payload length, but the memory
80 * block is independent of the payload's wire buffer. It is expected
81 * that both LocalControlHeader's and payload's wire will be send out
82 * together within a single send call.
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080083 *
84 * @see http://redmine.named-data.net/projects/nfd/wiki/LocalControlHeader
85 */
86 template<class U>
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080087 inline Block
88 wireEncode(const U& payload,
89 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070090
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080091 /**
92 * @brief Decode from the wire format and set LocalControlHeader on the supplied item
93 *
94 * The supplied wire MUST contain LocalControlHeader. Determination whether the optional
95 * LocalControlHeader should be done before calling this method.
96 */
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070097 inline void
Alexander Afanasyev37bb1902014-02-19 23:57:23 -080098 wireDecode(const Block& wire,
99 bool encodeIncomingFaceId = true, bool encodeNextHopFaceId = true);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800100
101 inline static const Block&
102 getPayload(const Block& wire);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700103
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800104 ///////////////////////////////////////////////////////////////////////////////
105 ///////////////////////////////////////////////////////////////////////////////
106 ///////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800107 // Getters/setters
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800108
109 bool
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800110 empty(bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800111 {
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800112 return !((encodeIncomingFaceId && hasIncomingFaceId()) ||
113 (encodeNextHopFaceId && hasNextHopFaceId()));
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800114 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700115
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800116 //
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700117
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800118 bool
119 hasIncomingFaceId() const
120 {
121 return m_incomingFaceId != INVALID_FACE_ID;
122 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700123
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800124 uint64_t
125 getIncomingFaceId() const
126 {
127 return m_incomingFaceId;
128 }
129
130 void
131 setIncomingFaceId(uint64_t incomingFaceId)
132 {
133 m_incomingFaceId = incomingFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800134 }
135
136 //
137
138 bool
139 hasNextHopFaceId() const
140 {
141 return m_nextHopFaceId != INVALID_FACE_ID;
142 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700143
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800144 uint64_t
145 getNextHopFaceId() const
146 {
147 return m_nextHopFaceId;
148 }
149
150 void
151 setNextHopFaceId(uint64_t nextHopFaceId)
152 {
153 m_nextHopFaceId = nextHopFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800154 }
155
156private:
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800157 template<bool T>
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800158 inline size_t
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800159 wireEncode(EncodingImpl<T>& block, size_t payloadSize,
160 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700161
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800162private:
163 uint64_t m_incomingFaceId;
164 uint64_t m_nextHopFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800165};
166
167
168/**
169 * @brief Fast encoding or block size estimation
170 */
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800171template<bool T>
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800172inline size_t
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800173LocalControlHeader::wireEncode(EncodingImpl<T>& block, size_t payloadSize,
174 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800175{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700176 size_t totalLength = payloadSize;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800177
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800178 if (encodeIncomingFaceId && hasIncomingFaceId())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800179 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700180 totalLength += prependNonNegativeIntegerBlock(block,
181 tlv::nfd::IncomingFaceId, getIncomingFaceId());
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800182 }
183
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800184 if (encodeNextHopFaceId && hasNextHopFaceId())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800185 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700186 totalLength += prependNonNegativeIntegerBlock(block,
187 tlv::nfd::NextHopFaceId, getNextHopFaceId());
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800188 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700189
190 totalLength += block.prependVarNumber(totalLength);
191 totalLength += block.prependVarNumber(tlv::nfd::LocalControlHeader);
192 return totalLength;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800193}
194
195template<class U>
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800196inline Block
197LocalControlHeader::wireEncode(const U& payload,
198 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800199{
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800200 /// @todo should this be BOOST_ASSERT instead? This is kind of unnecessary overhead
201 if (empty(encodeIncomingFaceId, encodeNextHopFaceId))
202 throw Error("Requested wire for LocalControlHeader, but none of the fields are set or enabled");
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800203
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800204 EncodingEstimator estimator;
205 size_t length = wireEncode(estimator, payload.wireEncode().size(),
206 encodeIncomingFaceId, encodeNextHopFaceId);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700207
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800208 EncodingBuffer buffer(length);
209 wireEncode(buffer, payload.wireEncode().size(),
210 encodeIncomingFaceId, encodeNextHopFaceId);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800211
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800212 return buffer.block(false);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800213}
214
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700215inline void
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800216LocalControlHeader::wireDecode(const Block& wire,
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700217 bool encodeIncomingFaceId/* = true*/,
218 bool encodeNextHopFaceId/* = true*/)
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800219{
220 BOOST_ASSERT(wire.type() == tlv::nfd::LocalControlHeader);
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800221 wire.parse();
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800222
223 m_incomingFaceId = INVALID_FACE_ID;
224 m_nextHopFaceId = INVALID_FACE_ID;
225
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800226 for (Block::element_const_iterator i = wire.elements_begin();
227 i != wire.elements_end();
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800228 ++i)
229 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700230 switch (i->type())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800231 {
232 case tlv::nfd::IncomingFaceId:
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800233 if (encodeIncomingFaceId)
234 m_incomingFaceId = readNonNegativeInteger(*i);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800235 break;
236 case tlv::nfd::NextHopFaceId:
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800237 if (encodeNextHopFaceId)
238 m_nextHopFaceId = readNonNegativeInteger(*i);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800239 break;
240 default:
241 // ignore all unsupported
242 break;
243 }
244 }
245}
246
247inline const Block&
248LocalControlHeader::getPayload(const Block& wire)
249{
250 if (wire.type() == tlv::nfd::LocalControlHeader)
251 {
252 wire.parse();
253 if (wire.elements_size() < 1)
254 return wire; // don't throw an error, but don't continue processing
255
256 return wire.elements()[wire.elements().size()-1];
257 }
258 else
259 {
260 return wire;
261 }
262}
263
264
265} // namespace nfd
266} // namespace ndn
267
268#endif // NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP