blob: 9bbdebffbdcc626cdd619fe6c0c8fe79ec190bd4 [file] [log] [blame]
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
3 * Copyright (C) 2013 Regents of the University of California.
4 * See COPYING for copyright and distribution information.
5 */
6
7#ifndef NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP
8#define NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP
9
10#include "../encoding/encoding-buffer.hpp"
11#include "../encoding/tlv-nfd.hpp"
12
13namespace ndn {
14namespace nfd {
15
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080016class LocalControlHeader
17{
18public:
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070019 class Error : public std::runtime_error
20 {
21 public:
22 explicit
23 Error(const std::string& what)
24 : std::runtime_error(what)
25 {
26 }
27 };
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080028
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080029 LocalControlHeader()
30 : m_incomingFaceId(INVALID_FACE_ID)
31 , m_nextHopFaceId(INVALID_FACE_ID)
32 {
33 }
34
35 /**
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070036 * @brief Create from wire encoding
37 *
38 * @sa wireDecode
39 */
40 explicit
41 LocalControlHeader(const Block& wire,
42 bool encodeIncomingFaceId = true, bool encodeNextHopFaceId = true)
43 {
44 wireDecode(wire, encodeIncomingFaceId, encodeNextHopFaceId);
45 }
46
47 /**
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080048 * @brief Create wire encoding with options LocalControlHeader and the supplied item
49 *
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080050 * The caller is responsible of checking whether LocalControlHeader contains
51 * any information.
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080052 *
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080053 * !It is an error to call this method if neither IncomingFaceId nor NextHopFaceId is
54 * set, or neither of them is enabled.
55 *
56 * @throws LocalControlHeader::Error when empty LocalControlHeader be produced
57 *
58 * @returns Block, containing LocalControlHeader. Top-level length field of the
59 * returned LocalControlHeader includes payload length, but the memory
60 * block is independent of the payload's wire buffer. It is expected
61 * that both LocalControlHeader's and payload's wire will be send out
62 * together within a single send call.
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080063 *
64 * @see http://redmine.named-data.net/projects/nfd/wiki/LocalControlHeader
65 */
66 template<class U>
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080067 inline Block
68 wireEncode(const U& payload,
69 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070070
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080071 /**
72 * @brief Decode from the wire format and set LocalControlHeader on the supplied item
73 *
74 * The supplied wire MUST contain LocalControlHeader. Determination whether the optional
75 * LocalControlHeader should be done before calling this method.
76 */
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070077 inline void
Alexander Afanasyev37bb1902014-02-19 23:57:23 -080078 wireDecode(const Block& wire,
79 bool encodeIncomingFaceId = true, bool encodeNextHopFaceId = true);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080080
81 inline static const Block&
82 getPayload(const Block& wire);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070083
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080084 ///////////////////////////////////////////////////////////////////////////////
85 ///////////////////////////////////////////////////////////////////////////////
86 ///////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080087 // Getters/setters
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080088
89 bool
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080090 empty(bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080091 {
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080092 return !((encodeIncomingFaceId && hasIncomingFaceId()) ||
93 (encodeNextHopFaceId && hasNextHopFaceId()));
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080094 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070095
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080096 //
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070097
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080098 bool
99 hasIncomingFaceId() const
100 {
101 return m_incomingFaceId != INVALID_FACE_ID;
102 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700103
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800104 uint64_t
105 getIncomingFaceId() const
106 {
107 return m_incomingFaceId;
108 }
109
110 void
111 setIncomingFaceId(uint64_t incomingFaceId)
112 {
113 m_incomingFaceId = incomingFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800114 }
115
116 //
117
118 bool
119 hasNextHopFaceId() const
120 {
121 return m_nextHopFaceId != INVALID_FACE_ID;
122 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700123
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800124 uint64_t
125 getNextHopFaceId() const
126 {
127 return m_nextHopFaceId;
128 }
129
130 void
131 setNextHopFaceId(uint64_t nextHopFaceId)
132 {
133 m_nextHopFaceId = nextHopFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800134 }
135
136private:
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800137 template<bool T>
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800138 inline size_t
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800139 wireEncode(EncodingImpl<T>& block, size_t payloadSize,
140 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700141
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800142private:
143 uint64_t m_incomingFaceId;
144 uint64_t m_nextHopFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800145};
146
147
148/**
149 * @brief Fast encoding or block size estimation
150 */
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800151template<bool T>
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800152inline size_t
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800153LocalControlHeader::wireEncode(EncodingImpl<T>& block, size_t payloadSize,
154 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800155{
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700156 size_t totalLength = payloadSize;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800157
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800158 if (encodeIncomingFaceId && hasIncomingFaceId())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800159 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700160 totalLength += prependNonNegativeIntegerBlock(block,
161 tlv::nfd::IncomingFaceId, getIncomingFaceId());
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800162 }
163
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800164 if (encodeNextHopFaceId && hasNextHopFaceId())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800165 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700166 totalLength += prependNonNegativeIntegerBlock(block,
167 tlv::nfd::NextHopFaceId, getNextHopFaceId());
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800168 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700169
170 totalLength += block.prependVarNumber(totalLength);
171 totalLength += block.prependVarNumber(tlv::nfd::LocalControlHeader);
172 return totalLength;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800173}
174
175template<class U>
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800176inline Block
177LocalControlHeader::wireEncode(const U& payload,
178 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800179{
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800180 /// @todo should this be BOOST_ASSERT instead? This is kind of unnecessary overhead
181 if (empty(encodeIncomingFaceId, encodeNextHopFaceId))
182 throw Error("Requested wire for LocalControlHeader, but none of the fields are set or enabled");
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800183
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800184 EncodingEstimator estimator;
185 size_t length = wireEncode(estimator, payload.wireEncode().size(),
186 encodeIncomingFaceId, encodeNextHopFaceId);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700187
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800188 EncodingBuffer buffer(length);
189 wireEncode(buffer, payload.wireEncode().size(),
190 encodeIncomingFaceId, encodeNextHopFaceId);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800191
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800192 return buffer.block(false);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800193}
194
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700195inline void
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800196LocalControlHeader::wireDecode(const Block& wire,
197 bool encodeIncomingFaceId/* = true*/, bool encodeNextHopFaceId/* = true*/)
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800198{
199 BOOST_ASSERT(wire.type() == tlv::nfd::LocalControlHeader);
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800200 wire.parse();
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800201
202 m_incomingFaceId = INVALID_FACE_ID;
203 m_nextHopFaceId = INVALID_FACE_ID;
204
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800205 for (Block::element_const_iterator i = wire.elements_begin();
206 i != wire.elements_end();
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800207 ++i)
208 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700209 switch (i->type())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800210 {
211 case tlv::nfd::IncomingFaceId:
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800212 if (encodeIncomingFaceId)
213 m_incomingFaceId = readNonNegativeInteger(*i);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800214 break;
215 case tlv::nfd::NextHopFaceId:
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800216 if (encodeNextHopFaceId)
217 m_nextHopFaceId = readNonNegativeInteger(*i);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800218 break;
219 default:
220 // ignore all unsupported
221 break;
222 }
223 }
224}
225
226inline const Block&
227LocalControlHeader::getPayload(const Block& wire)
228{
229 if (wire.type() == tlv::nfd::LocalControlHeader)
230 {
231 wire.parse();
232 if (wire.elements_size() < 1)
233 return wire; // don't throw an error, but don't continue processing
234
235 return wire.elements()[wire.elements().size()-1];
236 }
237 else
238 {
239 return wire;
240 }
241}
242
243
244} // namespace nfd
245} // namespace ndn
246
247#endif // NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP