blob: e53ae0ec24246e6c8cdfa25d1a26d9394c34c231 [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,
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700197 bool encodeIncomingFaceId/* = true*/,
198 bool encodeNextHopFaceId/* = true*/)
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800199{
200 BOOST_ASSERT(wire.type() == tlv::nfd::LocalControlHeader);
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800201 wire.parse();
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800202
203 m_incomingFaceId = INVALID_FACE_ID;
204 m_nextHopFaceId = INVALID_FACE_ID;
205
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800206 for (Block::element_const_iterator i = wire.elements_begin();
207 i != wire.elements_end();
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800208 ++i)
209 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700210 switch (i->type())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800211 {
212 case tlv::nfd::IncomingFaceId:
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800213 if (encodeIncomingFaceId)
214 m_incomingFaceId = readNonNegativeInteger(*i);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800215 break;
216 case tlv::nfd::NextHopFaceId:
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800217 if (encodeNextHopFaceId)
218 m_nextHopFaceId = readNonNegativeInteger(*i);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800219 break;
220 default:
221 // ignore all unsupported
222 break;
223 }
224 }
225}
226
227inline const Block&
228LocalControlHeader::getPayload(const Block& wire)
229{
230 if (wire.type() == tlv::nfd::LocalControlHeader)
231 {
232 wire.parse();
233 if (wire.elements_size() < 1)
234 return wire; // don't throw an error, but don't continue processing
235
236 return wire.elements()[wire.elements().size()-1];
237 }
238 else
239 {
240 return wire;
241 }
242}
243
244
245} // namespace nfd
246} // namespace ndn
247
248#endif // NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP