blob: e3bbe0ceb82266f26ea0a61d3d85cec5a54e873b [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
58 wireDecode(const Block& wire);
59
60 inline static const Block&
61 getPayload(const Block& wire);
62
63 ///////////////////////////////////////////////////////////////////////////////
64 ///////////////////////////////////////////////////////////////////////////////
65 ///////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080066 // Getters/setters
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080067
68 bool
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080069 empty(bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080070 {
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080071 return !((encodeIncomingFaceId && hasIncomingFaceId()) ||
72 (encodeNextHopFaceId && hasNextHopFaceId()));
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080073 }
74
75 //
76
77 bool
78 hasIncomingFaceId() const
79 {
80 return m_incomingFaceId != INVALID_FACE_ID;
81 }
82
83 uint64_t
84 getIncomingFaceId() const
85 {
86 return m_incomingFaceId;
87 }
88
89 void
90 setIncomingFaceId(uint64_t incomingFaceId)
91 {
92 m_incomingFaceId = incomingFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080093 }
94
95 //
96
97 bool
98 hasNextHopFaceId() const
99 {
100 return m_nextHopFaceId != INVALID_FACE_ID;
101 }
102
103 uint64_t
104 getNextHopFaceId() const
105 {
106 return m_nextHopFaceId;
107 }
108
109 void
110 setNextHopFaceId(uint64_t nextHopFaceId)
111 {
112 m_nextHopFaceId = nextHopFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800113 }
114
115private:
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800116 template<bool T>
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800117 inline size_t
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800118 wireEncode(EncodingImpl<T>& block, size_t payloadSize,
119 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800120
121private:
122 uint64_t m_incomingFaceId;
123 uint64_t m_nextHopFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800124};
125
126
127/**
128 * @brief Fast encoding or block size estimation
129 */
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800130template<bool T>
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800131inline size_t
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800132LocalControlHeader::wireEncode(EncodingImpl<T>& block, size_t payloadSize,
133 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800134{
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800135 size_t total_len = payloadSize;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800136
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800137 if (encodeIncomingFaceId && hasIncomingFaceId())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800138 {
139 total_len += prependNonNegativeIntegerBlock(block,
140 tlv::nfd::IncomingFaceId, getIncomingFaceId());
141 }
142
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800143 if (encodeNextHopFaceId && hasNextHopFaceId())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800144 {
145 total_len += prependNonNegativeIntegerBlock(block,
146 tlv::nfd::NextHopFaceId, getNextHopFaceId());
147 }
148
149 total_len += block.prependVarNumber(total_len);
150 total_len += block.prependVarNumber(tlv::nfd::LocalControlHeader);
151 return total_len;
152}
153
154template<class U>
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800155inline Block
156LocalControlHeader::wireEncode(const U& payload,
157 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800158{
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800159 /// @todo should this be BOOST_ASSERT instead? This is kind of unnecessary overhead
160 if (empty(encodeIncomingFaceId, encodeNextHopFaceId))
161 throw Error("Requested wire for LocalControlHeader, but none of the fields are set or enabled");
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800162
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800163 EncodingEstimator estimator;
164 size_t length = wireEncode(estimator, payload.wireEncode().size(),
165 encodeIncomingFaceId, encodeNextHopFaceId);
166
167 EncodingBuffer buffer(length);
168 wireEncode(buffer, payload.wireEncode().size(),
169 encodeIncomingFaceId, encodeNextHopFaceId);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800170
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800171 return buffer.block(false);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800172}
173
174inline void
175LocalControlHeader::wireDecode(const Block& wire)
176{
177 BOOST_ASSERT(wire.type() == tlv::nfd::LocalControlHeader);
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800178 wire.parse();
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800179
180 m_incomingFaceId = INVALID_FACE_ID;
181 m_nextHopFaceId = INVALID_FACE_ID;
182
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800183 for (Block::element_const_iterator i = wire.elements_begin();
184 i != wire.elements_end();
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800185 ++i)
186 {
187 switch(i->type())
188 {
189 case tlv::nfd::IncomingFaceId:
190 m_incomingFaceId = readNonNegativeInteger(*i);
191 break;
192 case tlv::nfd::NextHopFaceId:
193 m_nextHopFaceId = readNonNegativeInteger(*i);
194 break;
195 default:
196 // ignore all unsupported
197 break;
198 }
199 }
200}
201
202inline const Block&
203LocalControlHeader::getPayload(const Block& wire)
204{
205 if (wire.type() == tlv::nfd::LocalControlHeader)
206 {
207 wire.parse();
208 if (wire.elements_size() < 1)
209 return wire; // don't throw an error, but don't continue processing
210
211 return wire.elements()[wire.elements().size()-1];
212 }
213 else
214 {
215 return wire;
216 }
217}
218
219
220} // namespace nfd
221} // namespace ndn
222
223#endif // NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP