blob: 5ddc14bb2dc82b471848a38a47ac0497f96c0b67 [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();
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080017
18class LocalControlHeader
19{
20public:
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080021 struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
22
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080023 LocalControlHeader()
24 : m_incomingFaceId(INVALID_FACE_ID)
25 , m_nextHopFaceId(INVALID_FACE_ID)
26 {
27 }
28
29 /**
30 * @brief Create wire encoding with options LocalControlHeader and the supplied item
31 *
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080032 * The caller is responsible of checking whether LocalControlHeader contains
33 * any information.
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080034 *
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080035 * !It is an error to call this method if neither IncomingFaceId nor NextHopFaceId is
36 * set, or neither of them is enabled.
37 *
38 * @throws LocalControlHeader::Error when empty LocalControlHeader be produced
39 *
40 * @returns Block, containing LocalControlHeader. Top-level length field of the
41 * returned LocalControlHeader includes payload length, but the memory
42 * block is independent of the payload's wire buffer. It is expected
43 * that both LocalControlHeader's and payload's wire will be send out
44 * together within a single send call.
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080045 *
46 * @see http://redmine.named-data.net/projects/nfd/wiki/LocalControlHeader
47 */
48 template<class U>
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080049 inline Block
50 wireEncode(const U& payload,
51 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080052
53 /**
54 * @brief Decode from the wire format and set LocalControlHeader on the supplied item
55 *
56 * The supplied wire MUST contain LocalControlHeader. Determination whether the optional
57 * LocalControlHeader should be done before calling this method.
58 */
59 inline void
60 wireDecode(const Block& wire);
61
62 inline static const Block&
63 getPayload(const Block& wire);
64
65 ///////////////////////////////////////////////////////////////////////////////
66 ///////////////////////////////////////////////////////////////////////////////
67 ///////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080068 // Getters/setters
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080069
70 bool
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080071 empty(bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080072 {
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080073 return !((encodeIncomingFaceId && hasIncomingFaceId()) ||
74 (encodeNextHopFaceId && hasNextHopFaceId()));
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080075 }
76
77 //
78
79 bool
80 hasIncomingFaceId() const
81 {
82 return m_incomingFaceId != INVALID_FACE_ID;
83 }
84
85 uint64_t
86 getIncomingFaceId() const
87 {
88 return m_incomingFaceId;
89 }
90
91 void
92 setIncomingFaceId(uint64_t incomingFaceId)
93 {
94 m_incomingFaceId = incomingFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -080095 }
96
97 //
98
99 bool
100 hasNextHopFaceId() const
101 {
102 return m_nextHopFaceId != INVALID_FACE_ID;
103 }
104
105 uint64_t
106 getNextHopFaceId() const
107 {
108 return m_nextHopFaceId;
109 }
110
111 void
112 setNextHopFaceId(uint64_t nextHopFaceId)
113 {
114 m_nextHopFaceId = nextHopFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800115 }
116
117private:
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800118 template<bool T>
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800119 inline size_t
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800120 wireEncode(EncodingImpl<T>& block, size_t payloadSize,
121 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800122
123private:
124 uint64_t m_incomingFaceId;
125 uint64_t m_nextHopFaceId;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800126};
127
128
129/**
130 * @brief Fast encoding or block size estimation
131 */
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800132template<bool T>
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800133inline size_t
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800134LocalControlHeader::wireEncode(EncodingImpl<T>& block, size_t payloadSize,
135 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800136{
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800137 size_t total_len = payloadSize;
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800138
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800139 if (encodeIncomingFaceId && hasIncomingFaceId())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800140 {
141 total_len += prependNonNegativeIntegerBlock(block,
142 tlv::nfd::IncomingFaceId, getIncomingFaceId());
143 }
144
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800145 if (encodeNextHopFaceId && hasNextHopFaceId())
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800146 {
147 total_len += prependNonNegativeIntegerBlock(block,
148 tlv::nfd::NextHopFaceId, getNextHopFaceId());
149 }
150
151 total_len += block.prependVarNumber(total_len);
152 total_len += block.prependVarNumber(tlv::nfd::LocalControlHeader);
153 return total_len;
154}
155
156template<class U>
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800157inline Block
158LocalControlHeader::wireEncode(const U& payload,
159 bool encodeIncomingFaceId, bool encodeNextHopFaceId) const
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800160{
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800161 /// @todo should this be BOOST_ASSERT instead? This is kind of unnecessary overhead
162 if (empty(encodeIncomingFaceId, encodeNextHopFaceId))
163 throw Error("Requested wire for LocalControlHeader, but none of the fields are set or enabled");
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800164
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800165 EncodingEstimator estimator;
166 size_t length = wireEncode(estimator, payload.wireEncode().size(),
167 encodeIncomingFaceId, encodeNextHopFaceId);
168
169 EncodingBuffer buffer(length);
170 wireEncode(buffer, payload.wireEncode().size(),
171 encodeIncomingFaceId, encodeNextHopFaceId);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800172
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800173 return buffer.block(false);
Alexander Afanasyev6d48bc12014-02-18 00:10:51 -0800174}
175
176inline void
177LocalControlHeader::wireDecode(const Block& wire)
178{
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:
192 m_incomingFaceId = readNonNegativeInteger(*i);
193 break;
194 case tlv::nfd::NextHopFaceId:
195 m_nextHopFaceId = readNonNegativeInteger(*i);
196 break;
197 default:
198 // ignore all unsupported
199 break;
200 }
201 }
202}
203
204inline const Block&
205LocalControlHeader::getPayload(const Block& wire)
206{
207 if (wire.type() == tlv::nfd::LocalControlHeader)
208 {
209 wire.parse();
210 if (wire.elements_size() < 1)
211 return wire; // don't throw an error, but don't continue processing
212
213 return wire.elements()[wire.elements().size()-1];
214 }
215 else
216 {
217 return wire;
218 }
219}
220
221
222} // namespace nfd
223} // namespace ndn
224
225#endif // NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP