blob: d09fe8ad15da9db4c1b31c0cdd055643caeec62f [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 Afanasyev5964fb72014-02-18 12:42:45 -080019 struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
20
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080021 LocalControlHeader()
22 : m_incomingFaceId(INVALID_FACE_ID)
23 , m_nextHopFaceId(INVALID_FACE_ID)
24 {
25 }
26
27 /**
28 * @brief Create wire encoding with options LocalControlHeader and the supplied item
29 *
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080030 * The caller is responsible of checking whether LocalControlHeader contains
31 * any information.
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080032 *
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080033 * !It is an error to call this method if neither IncomingFaceId nor NextHopFaceId is
34 * set, or neither of them is enabled.
35 *
36 * @throws LocalControlHeader::Error when empty LocalControlHeader be produced
37 *
38 * @returns Block, containing LocalControlHeader. Top-level length field of the
39 * returned LocalControlHeader includes payload length, but the memory
40 * block is independent of the payload's wire buffer. It is expected
41 * that both LocalControlHeader's and payload's wire will be send out
42 * together within a single send call.
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080043 *
44 * @see http://redmine.named-data.net/projects/nfd/wiki/LocalControlHeader
45 */
46 template<class U>
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080047 inline Block
48 wireEncode(const U& payload,
49 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080050
51 /**
52 * @brief Decode from the wire format and set LocalControlHeader on the supplied item
53 *
54 * The supplied wire MUST contain LocalControlHeader. Determination whether the optional
55 * LocalControlHeader should be done before calling this method.
56 */
57 inline void
Alexander Afanasyev37bb1902014-02-19 23:57:23 -080058 wireDecode(const Block& wire,
59 bool encodeIncomingFaceId = true, bool encodeNextHopFaceId = true);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080060
61 inline static const Block&
62 getPayload(const Block& wire);
63
64 ///////////////////////////////////////////////////////////////////////////////
65 ///////////////////////////////////////////////////////////////////////////////
66 ///////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080067 // Getters/setters
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080068
69 bool
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080070 empty(bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080071 {
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080072 return !((encodeIncomingFaceId && hasIncomingFaceId()) ||
73 (encodeNextHopFaceId && hasNextHopFaceId()));
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080074 }
75
76 //
77
78 bool
79 hasIncomingFaceId() const
80 {
81 return m_incomingFaceId != INVALID_FACE_ID;
82 }
83
84 uint64_t
85 getIncomingFaceId() const
86 {
87 return m_incomingFaceId;
88 }
89
90 void
91 setIncomingFaceId(uint64_t incomingFaceId)
92 {
93 m_incomingFaceId = incomingFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080094 }
95
96 //
97
98 bool
99 hasNextHopFaceId() const
100 {
101 return m_nextHopFaceId != INVALID_FACE_ID;
102 }
103
104 uint64_t
105 getNextHopFaceId() const
106 {
107 return m_nextHopFaceId;
108 }
109
110 void
111 setNextHopFaceId(uint64_t nextHopFaceId)
112 {
113 m_nextHopFaceId = nextHopFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800114 }
115
116private:
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800117 template<bool T>
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800118 inline size_t
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800119 wireEncode(EncodingImpl<T>& block, size_t payloadSize,
120 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800121
122private:
123 uint64_t m_incomingFaceId;
124 uint64_t m_nextHopFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800125};
126
127
128/**
129 * @brief Fast encoding or block size estimation
130 */
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800131template<bool T>
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800132inline size_t
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800133LocalControlHeader::wireEncode(EncodingImpl<T>& block, size_t payloadSize,
134 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800135{
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800136 size_t total_len = payloadSize;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800137
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800138 if (encodeIncomingFaceId && hasIncomingFaceId())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800139 {
140 total_len += prependNonNegativeIntegerBlock(block,
141 tlv::nfd::IncomingFaceId, getIncomingFaceId());
142 }
143
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800144 if (encodeNextHopFaceId && hasNextHopFaceId())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800145 {
146 total_len += prependNonNegativeIntegerBlock(block,
147 tlv::nfd::NextHopFaceId, getNextHopFaceId());
148 }
149
150 total_len += block.prependVarNumber(total_len);
151 total_len += block.prependVarNumber(tlv::nfd::LocalControlHeader);
152 return total_len;
153}
154
155template<class U>
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800156inline Block
157LocalControlHeader::wireEncode(const U& payload,
158 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800159{
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800160 /// @todo should this be BOOST_ASSERT instead? This is kind of unnecessary overhead
161 if (empty(encodeIncomingFaceId, encodeNextHopFaceId))
162 throw Error("Requested wire for LocalControlHeader, but none of the fields are set or enabled");
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800163
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800164 EncodingEstimator estimator;
165 size_t length = wireEncode(estimator, payload.wireEncode().size(),
166 encodeIncomingFaceId, encodeNextHopFaceId);
167
168 EncodingBuffer buffer(length);
169 wireEncode(buffer, payload.wireEncode().size(),
170 encodeIncomingFaceId, encodeNextHopFaceId);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800171
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800172 return buffer.block(false);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800173}
174
175inline void
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800176LocalControlHeader::wireDecode(const Block& wire,
177 bool encodeIncomingFaceId/* = true*/, bool encodeNextHopFaceId/* = true*/)
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800178{
179 BOOST_ASSERT(wire.type() == tlv::nfd::LocalControlHeader);
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800180 wire.parse();
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800181
182 m_incomingFaceId = INVALID_FACE_ID;
183 m_nextHopFaceId = INVALID_FACE_ID;
184
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800185 for (Block::element_const_iterator i = wire.elements_begin();
186 i != wire.elements_end();
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800187 ++i)
188 {
189 switch(i->type())
190 {
191 case tlv::nfd::IncomingFaceId:
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800192 if (encodeIncomingFaceId)
193 m_incomingFaceId = readNonNegativeInteger(*i);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800194 break;
195 case tlv::nfd::NextHopFaceId:
Alexander Afanasyev37bb1902014-02-19 23:57:23 -0800196 if (encodeNextHopFaceId)
197 m_nextHopFaceId = readNonNegativeInteger(*i);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800198 break;
199 default:
200 // ignore all unsupported
201 break;
202 }
203 }
204}
205
206inline const Block&
207LocalControlHeader::getPayload(const Block& wire)
208{
209 if (wire.type() == tlv::nfd::LocalControlHeader)
210 {
211 wire.parse();
212 if (wire.elements_size() < 1)
213 return wire; // don't throw an error, but don't continue processing
214
215 return wire.elements()[wire.elements().size()-1];
216 }
217 else
218 {
219 return wire;
220 }
221}
222
223
224} // namespace nfd
225} // namespace ndn
226
227#endif // NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP