blob: fc73b5081f627d945a66abde8108fde4d81a2405 [file] [log] [blame]
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07003 * Copyright (c) 2013-2014, Regents of the University of California.
4 * All rights reserved.
5 *
6 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
7 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
8 *
9 * This file licensed under New BSD License. See COPYING for detailed information about
10 * ndn-cxx library copyright, permissions, and redistribution restrictions.
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080011 */
12
13#ifndef NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP
14#define NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP
15
16#include "../encoding/encoding-buffer.hpp"
17#include "../encoding/tlv-nfd.hpp"
18
19namespace ndn {
20namespace nfd {
21
Alexander Afanasyev4671bf72014-05-19 09:01:37 -040022/**
23 * @ingroup management
24 * @brief Class to handle work with LocalControlHeader
25 * @sa http://redmine.named-data.net/projects/nfd/wiki/LocalControlHeader
26 */
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080027class LocalControlHeader
28{
29public:
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070030 class Error : public std::runtime_error
31 {
32 public:
33 explicit
34 Error(const std::string& what)
35 : std::runtime_error(what)
36 {
37 }
38 };
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080039
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080040 LocalControlHeader()
41 : m_incomingFaceId(INVALID_FACE_ID)
42 , m_nextHopFaceId(INVALID_FACE_ID)
43 {
44 }
45
46 /**
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070047 * @brief Create from wire encoding
48 *
49 * @sa wireDecode
50 */
51 explicit
52 LocalControlHeader(const Block& wire,
53 bool encodeIncomingFaceId = true, bool encodeNextHopFaceId = true)
54 {
55 wireDecode(wire, encodeIncomingFaceId, encodeNextHopFaceId);
56 }
57
58 /**
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080059 * @brief Create wire encoding with options LocalControlHeader and the supplied item
60 *
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080061 * The caller is responsible of checking whether LocalControlHeader contains
62 * any information.
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080063 *
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080064 * !It is an error to call this method if neither IncomingFaceId nor NextHopFaceId is
65 * set, or neither of them is enabled.
66 *
67 * @throws LocalControlHeader::Error when empty LocalControlHeader be produced
68 *
69 * @returns Block, containing LocalControlHeader. Top-level length field of the
70 * returned LocalControlHeader includes payload length, but the memory
71 * block is independent of the payload's wire buffer. It is expected
72 * that both LocalControlHeader's and payload's wire will be send out
73 * together within a single send call.
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080074 *
75 * @see http://redmine.named-data.net/projects/nfd/wiki/LocalControlHeader
76 */
77 template<class U>
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080078 inline Block
79 wireEncode(const U& payload,
80 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070081
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080082 /**
83 * @brief Decode from the wire format and set LocalControlHeader on the supplied item
84 *
85 * The supplied wire MUST contain LocalControlHeader. Determination whether the optional
86 * LocalControlHeader should be done before calling this method.
87 */
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070088 inline void
Alexander Afanasyev37bb1902014-02-19 23:57:23 -080089 wireDecode(const Block& wire,
90 bool encodeIncomingFaceId = true, bool encodeNextHopFaceId = true);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080091
92 inline static const Block&
93 getPayload(const Block& wire);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070094
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080095 ///////////////////////////////////////////////////////////////////////////////
96 ///////////////////////////////////////////////////////////////////////////////
97 ///////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080098 // Getters/setters
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080099
100 bool
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800101 empty(bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800102 {
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800103 return !((encodeIncomingFaceId && hasIncomingFaceId()) ||
104 (encodeNextHopFaceId && hasNextHopFaceId()));
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800105 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700106
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800107 //
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700108
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800109 bool
110 hasIncomingFaceId() const
111 {
112 return m_incomingFaceId != INVALID_FACE_ID;
113 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700114
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800115 uint64_t
116 getIncomingFaceId() const
117 {
118 return m_incomingFaceId;
119 }
120
121 void
122 setIncomingFaceId(uint64_t incomingFaceId)
123 {
124 m_incomingFaceId = incomingFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800125 }
126
127 //
128
129 bool
130 hasNextHopFaceId() const
131 {
132 return m_nextHopFaceId != INVALID_FACE_ID;
133 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700134
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800135 uint64_t
136 getNextHopFaceId() const
137 {
138 return m_nextHopFaceId;
139 }
140
141 void
142 setNextHopFaceId(uint64_t nextHopFaceId)
143 {
144 m_nextHopFaceId = nextHopFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800145 }
146
147private:
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800148 template<bool T>
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800149 inline size_t
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800150 wireEncode(EncodingImpl<T>& block, size_t payloadSize,
151 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700152
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800153private:
154 uint64_t m_incomingFaceId;
155 uint64_t m_nextHopFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800156};
157
158
159/**
160 * @brief Fast encoding or block size estimation
161 */
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800162template<bool T>
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800163inline size_t
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800164LocalControlHeader::wireEncode(EncodingImpl<T>& block, size_t payloadSize,
165 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800166{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700167 size_t totalLength = payloadSize;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800168
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800169 if (encodeIncomingFaceId && hasIncomingFaceId())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800170 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700171 totalLength += prependNonNegativeIntegerBlock(block,
172 tlv::nfd::IncomingFaceId, getIncomingFaceId());
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800173 }
174
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800175 if (encodeNextHopFaceId && hasNextHopFaceId())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800176 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700177 totalLength += prependNonNegativeIntegerBlock(block,
178 tlv::nfd::NextHopFaceId, getNextHopFaceId());
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800179 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700180
181 totalLength += block.prependVarNumber(totalLength);
182 totalLength += block.prependVarNumber(tlv::nfd::LocalControlHeader);
183 return totalLength;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800184}
185
186template<class U>
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800187inline Block
188LocalControlHeader::wireEncode(const U& payload,
189 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800190{
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800191 /// @todo should this be BOOST_ASSERT instead? This is kind of unnecessary overhead
192 if (empty(encodeIncomingFaceId, encodeNextHopFaceId))
193 throw Error("Requested wire for LocalControlHeader, but none of the fields are set or enabled");
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800194
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800195 EncodingEstimator estimator;
196 size_t length = wireEncode(estimator, payload.wireEncode().size(),
197 encodeIncomingFaceId, encodeNextHopFaceId);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700198
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800199 EncodingBuffer buffer(length);
200 wireEncode(buffer, payload.wireEncode().size(),
201 encodeIncomingFaceId, encodeNextHopFaceId);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800202
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800203 return buffer.block(false);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800204}
205
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700206inline void
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800207LocalControlHeader::wireDecode(const Block& wire,
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700208 bool encodeIncomingFaceId/* = true*/,
209 bool encodeNextHopFaceId/* = true*/)
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800210{
211 BOOST_ASSERT(wire.type() == tlv::nfd::LocalControlHeader);
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800212 wire.parse();
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800213
214 m_incomingFaceId = INVALID_FACE_ID;
215 m_nextHopFaceId = INVALID_FACE_ID;
216
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800217 for (Block::element_const_iterator i = wire.elements_begin();
218 i != wire.elements_end();
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800219 ++i)
220 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700221 switch (i->type())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800222 {
223 case tlv::nfd::IncomingFaceId:
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800224 if (encodeIncomingFaceId)
225 m_incomingFaceId = readNonNegativeInteger(*i);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800226 break;
227 case tlv::nfd::NextHopFaceId:
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800228 if (encodeNextHopFaceId)
229 m_nextHopFaceId = readNonNegativeInteger(*i);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800230 break;
231 default:
232 // ignore all unsupported
233 break;
234 }
235 }
236}
237
238inline const Block&
239LocalControlHeader::getPayload(const Block& wire)
240{
241 if (wire.type() == tlv::nfd::LocalControlHeader)
242 {
243 wire.parse();
244 if (wire.elements_size() < 1)
245 return wire; // don't throw an error, but don't continue processing
246
247 return wire.elements()[wire.elements().size()-1];
248 }
249 else
250 {
251 return wire;
252 }
253}
254
255
256} // namespace nfd
257} // namespace ndn
258
259#endif // NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP