blob: e931f57ca1dde90e8fa76aea0a930d52c539dcb4 [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
16const uint64_t INVALID_FACE_ID = std::numeric_limits<uint64_t>::max();
17const size_t ESTIMATED_LOCAL_HEADER_RESERVE = 10;
18
19class LocalControlHeader
20{
21public:
22 LocalControlHeader()
23 : m_incomingFaceId(INVALID_FACE_ID)
24 , m_nextHopFaceId(INVALID_FACE_ID)
25 {
26 }
27
28 /**
29 * @brief Create wire encoding with options LocalControlHeader and the supplied item
30 *
31 * This method will return wire encoding of the item if none of the LocalControlHeader
32 * fields are set, otherwise it will encapsulate the item inside LocalControlHeader
33 *
34 * Note that this method will use default maximum packet size (8800 bytes) during the
35 * encoding process.
36 *
37 * @see http://redmine.named-data.net/projects/nfd/wiki/LocalControlHeader
38 */
39 template<class U>
40 inline const Block&
41 wireEncode(const U& item) const;
42
43 /**
44 * @brief Decode from the wire format and set LocalControlHeader on the supplied item
45 *
46 * The supplied wire MUST contain LocalControlHeader. Determination whether the optional
47 * LocalControlHeader should be done before calling this method.
48 */
49 inline void
50 wireDecode(const Block& wire);
51
52 inline static const Block&
53 getPayload(const Block& wire);
54
55 ///////////////////////////////////////////////////////////////////////////////
56 ///////////////////////////////////////////////////////////////////////////////
57 ///////////////////////////////////////////////////////////////////////////////
58 // Gettest/setters
59
60 bool
61 empty() const
62 {
63 return (!hasIncomingFaceId() && !hasNextHopFaceId());
64 }
65
66 //
67
68 bool
69 hasIncomingFaceId() const
70 {
71 return m_incomingFaceId != INVALID_FACE_ID;
72 }
73
74 uint64_t
75 getIncomingFaceId() const
76 {
77 return m_incomingFaceId;
78 }
79
80 void
81 setIncomingFaceId(uint64_t incomingFaceId)
82 {
83 m_incomingFaceId = incomingFaceId;
84 m_wire.reset();
85 }
86
87 //
88
89 bool
90 hasNextHopFaceId() const
91 {
92 return m_nextHopFaceId != INVALID_FACE_ID;
93 }
94
95 uint64_t
96 getNextHopFaceId() const
97 {
98 return m_nextHopFaceId;
99 }
100
101 void
102 setNextHopFaceId(uint64_t nextHopFaceId)
103 {
104 m_nextHopFaceId = nextHopFaceId;
105 m_wire.reset();
106 }
107
108private:
109 template<bool T, class U>
110 inline size_t
111 wireEncode(EncodingImpl<T>& block, const U& item) const;
112
113private:
114 uint64_t m_incomingFaceId;
115 uint64_t m_nextHopFaceId;
116
117 mutable Block m_wire;
118};
119
120
121/**
122 * @brief Fast encoding or block size estimation
123 */
124template<bool T, class U>
125inline size_t
126LocalControlHeader::wireEncode(EncodingImpl<T>& block, const U& item) const
127{
128 size_t total_len = item.wireEncode().size();
129
130 if (hasIncomingFaceId())
131 {
132 total_len += prependNonNegativeIntegerBlock(block,
133 tlv::nfd::IncomingFaceId, getIncomingFaceId());
134 }
135
136 if (hasNextHopFaceId())
137 {
138 total_len += prependNonNegativeIntegerBlock(block,
139 tlv::nfd::NextHopFaceId, getNextHopFaceId());
140 }
141
142 total_len += block.prependVarNumber(total_len);
143 total_len += block.prependVarNumber(tlv::nfd::LocalControlHeader);
144 return total_len;
145}
146
147template<class U>
148inline const Block&
149LocalControlHeader::wireEncode(const U& item) const
150{
151 if (item.hasWire() && m_wire.hasWire())
152 return m_wire;
153
154 if (empty())
155 {
156 if (item.hasWire())
157 return item.wireEncode();
158 else
159 {
160 EncodingBuffer buffer; // use default (maximum) packet size here
161 item.wireEncode(buffer);
162 item.m_wire = buffer.block();
163 m_wire = buffer.block();
164 }
165 }
166 else
167 {
168 if (item.hasWire())
169 {
170 // extend the existing buffer
171 EncodingBuffer buffer(item.wireEncode());
172 wireEncode(buffer, item);
173 m_wire = buffer.block();
174 }
175 else
176 {
177 EncodingBuffer buffer;
178 item.wireEncode(buffer);
179 item.m_wire = buffer.block();
180
181 wireEncode(buffer, item);
182 m_wire = buffer.block();
183 }
184 }
185 return m_wire;
186}
187
188inline void
189LocalControlHeader::wireDecode(const Block& wire)
190{
191 BOOST_ASSERT(wire.type() == tlv::nfd::LocalControlHeader);
192 m_wire = wire;
193 m_wire.parse();
194
195 m_incomingFaceId = INVALID_FACE_ID;
196 m_nextHopFaceId = INVALID_FACE_ID;
197
198 for (Block::element_const_iterator i = m_wire.elements_begin();
199 i != m_wire.elements_end();
200 ++i)
201 {
202 switch(i->type())
203 {
204 case tlv::nfd::IncomingFaceId:
205 m_incomingFaceId = readNonNegativeInteger(*i);
206 break;
207 case tlv::nfd::NextHopFaceId:
208 m_nextHopFaceId = readNonNegativeInteger(*i);
209 break;
210 default:
211 // ignore all unsupported
212 break;
213 }
214 }
215}
216
217inline const Block&
218LocalControlHeader::getPayload(const Block& wire)
219{
220 if (wire.type() == tlv::nfd::LocalControlHeader)
221 {
222 wire.parse();
223 if (wire.elements_size() < 1)
224 return wire; // don't throw an error, but don't continue processing
225
226 return wire.elements()[wire.elements().size()-1];
227 }
228 else
229 {
230 return wire;
231 }
232}
233
234
235} // namespace nfd
236} // namespace ndn
237
238#endif // NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP