blob: 17b53d64b960bf91f815eb06386509714fbeb5c4 [file] [log] [blame]
Vince Lehmandbf3f702014-07-15 13:00:43 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Davide Pesaventof8503d22017-02-17 01:19:10 -05003 * Copyright (c) 2013-2017 Regents of the University of California.
Vince Lehmandbf3f702014-07-15 13:00:43 -05004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
Junxiao Shi7357ef22016-09-07 02:39:37 +000022#include "rib-entry.hpp"
Junxiao Shi65f1a712014-11-20 14:59:36 -070023#include "encoding/block-helpers.hpp"
Davide Pesavento484bbe52017-02-15 00:03:46 -050024#include "encoding/encoding-buffer.hpp"
25#include "encoding/tlv-nfd.hpp"
Junxiao Shi65f1a712014-11-20 14:59:36 -070026#include "util/concepts.hpp"
Vince Lehmandbf3f702014-07-15 13:00:43 -050027
Davide Pesavento484bbe52017-02-15 00:03:46 -050028#include <boost/range/adaptor/reversed.hpp>
29
Vince Lehmandbf3f702014-07-15 13:00:43 -050030namespace ndn {
31namespace nfd {
32
Davide Pesavento484bbe52017-02-15 00:03:46 -050033BOOST_CONCEPT_ASSERT((StatusDatasetItem<Route>));
34BOOST_CONCEPT_ASSERT((StatusDatasetItem<RibEntry>));
Vince Lehmandbf3f702014-07-15 13:00:43 -050035
36Route::Route()
Davide Pesaventof8503d22017-02-17 01:19:10 -050037 : m_faceId(INVALID_FACE_ID)
Vince Lehmandbf3f702014-07-15 13:00:43 -050038 , m_origin(0)
39 , m_cost(0)
40 , m_flags(ROUTE_FLAG_CHILD_INHERIT)
Vince Lehmandbf3f702014-07-15 13:00:43 -050041{
42}
43
44Route::Route(const Block& block)
45{
Davide Pesavento6ad3d532017-02-17 01:43:57 -050046 this->wireDecode(block);
47}
48
49Route&
50Route::setFaceId(uint64_t faceId)
51{
52 m_faceId = faceId;
53 m_wire.reset();
54 return *this;
55}
56
57Route&
58Route::setOrigin(uint64_t origin)
59{
60 m_origin = origin;
61 m_wire.reset();
62 return *this;
63}
64
65Route&
66Route::setCost(uint64_t cost)
67{
68 m_cost = cost;
69 m_wire.reset();
70 return *this;
71}
72
73Route&
74Route::setFlags(uint64_t flags)
75{
76 m_flags = flags;
77 m_wire.reset();
78 return *this;
79}
80
81Route&
82Route::setExpirationPeriod(time::milliseconds expirationPeriod)
83{
Davide Pesavento484bbe52017-02-15 00:03:46 -050084 if (expirationPeriod == time::milliseconds::max())
85 return unsetExpirationPeriod();
86
Davide Pesavento6ad3d532017-02-17 01:43:57 -050087 m_expirationPeriod = expirationPeriod;
Davide Pesavento484bbe52017-02-15 00:03:46 -050088 m_wire.reset();
89 return *this;
90}
91
92Route&
93Route::unsetExpirationPeriod()
94{
95 m_expirationPeriod = nullopt;
Davide Pesavento6ad3d532017-02-17 01:43:57 -050096 m_wire.reset();
97 return *this;
Vince Lehmandbf3f702014-07-15 13:00:43 -050098}
99
Alexander Afanasyev74633892015-02-08 18:08:46 -0800100template<encoding::Tag TAG>
Vince Lehmandbf3f702014-07-15 13:00:43 -0500101size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800102Route::wireEncode(EncodingImpl<TAG>& block) const
Vince Lehmandbf3f702014-07-15 13:00:43 -0500103{
104 size_t totalLength = 0;
105
Davide Pesavento484bbe52017-02-15 00:03:46 -0500106 if (m_expirationPeriod) {
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500107 totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::ExpirationPeriod,
Davide Pesavento484bbe52017-02-15 00:03:46 -0500108 static_cast<uint64_t>(m_expirationPeriod->count()));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500109 }
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500110 totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::Flags, m_flags);
111 totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::Cost, m_cost);
112 totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::Origin, m_origin);
113 totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::FaceId, m_faceId);
Vince Lehmandbf3f702014-07-15 13:00:43 -0500114
115 totalLength += block.prependVarNumber(totalLength);
116 totalLength += block.prependVarNumber(ndn::tlv::nfd::Route);
Vince Lehmandbf3f702014-07-15 13:00:43 -0500117 return totalLength;
118}
119
120template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800121Route::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& block) const;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500122
123template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800124Route::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& block) const;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500125
126const Block&
127Route::wireEncode() const
128{
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500129 if (m_wire.hasWire())
Vince Lehmandbf3f702014-07-15 13:00:43 -0500130 return m_wire;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500131
132 EncodingEstimator estimator;
133 size_t estimatedSize = wireEncode(estimator);
134
135 EncodingBuffer buffer(estimatedSize, 0);
136 wireEncode(buffer);
137
138 m_wire = buffer.block();
Vince Lehmandbf3f702014-07-15 13:00:43 -0500139 return m_wire;
140}
141
142void
Davide Pesavento484bbe52017-02-15 00:03:46 -0500143Route::wireDecode(const Block& block)
Vince Lehmandbf3f702014-07-15 13:00:43 -0500144{
Davide Pesavento484bbe52017-02-15 00:03:46 -0500145 if (block.type() != tlv::nfd::Route) {
146 BOOST_THROW_EXCEPTION(Error("expecting Route, but Block has type " + to_string(block.type())));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500147 }
Davide Pesavento484bbe52017-02-15 00:03:46 -0500148 m_wire = block;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500149 m_wire.parse();
Vince Lehmandbf3f702014-07-15 13:00:43 -0500150 Block::element_const_iterator val = m_wire.elements_begin();
151
152 if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceId) {
153 m_faceId = readNonNegativeInteger(*val);
154 ++val;
155 }
156 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500157 BOOST_THROW_EXCEPTION(Error("missing required FaceId field"));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500158 }
159
160 if (val != m_wire.elements_end() && val->type() == tlv::nfd::Origin) {
161 m_origin = readNonNegativeInteger(*val);
162 ++val;
163 }
164 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500165 BOOST_THROW_EXCEPTION(Error("missing required Origin field"));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500166 }
167
168 if (val != m_wire.elements_end() && val->type() == tlv::nfd::Cost) {
169 m_cost = readNonNegativeInteger(*val);
170 ++val;
171 }
172 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500173 BOOST_THROW_EXCEPTION(Error("missing required Cost field"));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500174 }
175
176 if (val != m_wire.elements_end() && val->type() == tlv::nfd::Flags) {
177 m_flags = readNonNegativeInteger(*val);
178 ++val;
179 }
180 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500181 BOOST_THROW_EXCEPTION(Error("missing required Flags field"));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500182 }
183
184 if (val != m_wire.elements_end() && val->type() == tlv::nfd::ExpirationPeriod) {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500185 m_expirationPeriod.emplace(readNonNegativeInteger(*val));
186 ++val;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500187 }
188 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500189 m_expirationPeriod = nullopt;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500190 }
191}
192
Davide Pesavento484bbe52017-02-15 00:03:46 -0500193bool
194operator==(const Route& a, const Route& b)
195{
196 return a.getFaceId() == b.getFaceId() &&
197 a.getOrigin() == b.getOrigin() &&
198 a.getCost() == b.getCost() &&
199 a.getFlags() == b.getFlags() &&
200 a.getExpirationPeriod() == b.getExpirationPeriod();
201}
202
Vince Lehmandbf3f702014-07-15 13:00:43 -0500203std::ostream&
204operator<<(std::ostream& os, const Route& route)
205{
206 os << "Route("
207 << "FaceId: " << route.getFaceId() << ", "
208 << "Origin: " << route.getOrigin() << ", "
Davide Pesavento484bbe52017-02-15 00:03:46 -0500209 << "Cost: " << route.getCost() << ", ";
Vince Lehmandbf3f702014-07-15 13:00:43 -0500210
Davide Pesavento484bbe52017-02-15 00:03:46 -0500211 auto osFlags = os.flags();
212 // std::showbase doesn't work with number 0
213 os << "Flags: 0x" << std::noshowbase << std::noshowpos << std::nouppercase
214 << std::hex << route.getFlags() << ", ";
215 os.flags(osFlags);
216
217 if (route.hasExpirationPeriod()) {
Vince Lehmandbf3f702014-07-15 13:00:43 -0500218 os << "ExpirationPeriod: " << route.getExpirationPeriod();
219 }
220 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500221 os << "ExpirationPeriod: infinite";
Vince Lehmandbf3f702014-07-15 13:00:43 -0500222 }
223
Davide Pesavento484bbe52017-02-15 00:03:46 -0500224 return os << ")";
Vince Lehmandbf3f702014-07-15 13:00:43 -0500225}
226
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500227////////////////////
Vince Lehmandbf3f702014-07-15 13:00:43 -0500228
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500229RibEntry::RibEntry() = default;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500230
231RibEntry::RibEntry(const Block& block)
232{
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500233 this->wireDecode(block);
Vince Lehmandbf3f702014-07-15 13:00:43 -0500234}
235
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500236RibEntry&
237RibEntry::setName(const Name& prefix)
238{
239 m_prefix = prefix;
240 m_wire.reset();
241 return *this;
242}
243
244RibEntry&
245RibEntry::addRoute(const Route& route)
246{
247 m_routes.push_back(route);
248 m_wire.reset();
249 return *this;
250}
251
252RibEntry&
253RibEntry::clearRoutes()
254{
255 m_routes.clear();
256 m_wire.reset();
257 return *this;
258}
Vince Lehmandbf3f702014-07-15 13:00:43 -0500259
Alexander Afanasyev74633892015-02-08 18:08:46 -0800260template<encoding::Tag TAG>
Vince Lehmandbf3f702014-07-15 13:00:43 -0500261size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800262RibEntry::wireEncode(EncodingImpl<TAG>& block) const
Vince Lehmandbf3f702014-07-15 13:00:43 -0500263{
264 size_t totalLength = 0;
265
Davide Pesavento484bbe52017-02-15 00:03:46 -0500266 for (const auto& route : m_routes | boost::adaptors::reversed) {
267 totalLength += route.wireEncode(block);
268 }
Vince Lehmandbf3f702014-07-15 13:00:43 -0500269 totalLength += m_prefix.wireEncode(block);
270
271 totalLength += block.prependVarNumber(totalLength);
272 totalLength += block.prependVarNumber(tlv::nfd::RibEntry);
Vince Lehmandbf3f702014-07-15 13:00:43 -0500273 return totalLength;
274}
275
276template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800277RibEntry::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& block) const;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500278
279template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800280RibEntry::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& block) const;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500281
282const Block&
283RibEntry::wireEncode() const
284{
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500285 if (m_wire.hasWire())
Vince Lehmandbf3f702014-07-15 13:00:43 -0500286 return m_wire;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500287
288 EncodingEstimator estimator;
289 size_t estimatedSize = wireEncode(estimator);
290
291 EncodingBuffer buffer(estimatedSize, 0);
292 wireEncode(buffer);
293
294 m_wire = buffer.block();
Vince Lehmandbf3f702014-07-15 13:00:43 -0500295 return m_wire;
296}
297
298void
Davide Pesavento484bbe52017-02-15 00:03:46 -0500299RibEntry::wireDecode(const Block& block)
Vince Lehmandbf3f702014-07-15 13:00:43 -0500300{
Davide Pesavento484bbe52017-02-15 00:03:46 -0500301 if (block.type() != tlv::nfd::RibEntry) {
302 BOOST_THROW_EXCEPTION(Error("expecting RibEntry, but Block has type " + to_string(block.type())));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500303 }
Davide Pesavento484bbe52017-02-15 00:03:46 -0500304 m_wire = block;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500305 m_wire.parse();
Vince Lehmandbf3f702014-07-15 13:00:43 -0500306 Block::element_const_iterator val = m_wire.elements_begin();
307
Davide Pesavento484bbe52017-02-15 00:03:46 -0500308 if (val == m_wire.elements_end()) {
309 BOOST_THROW_EXCEPTION(Error("unexpected end of RibEntry"));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500310 }
Davide Pesavento484bbe52017-02-15 00:03:46 -0500311 else if (val->type() != tlv::Name) {
312 BOOST_THROW_EXCEPTION(Error("expecting Name, but Block has type " + to_string(val->type())));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500313 }
Davide Pesavento484bbe52017-02-15 00:03:46 -0500314 m_prefix.wireDecode(*val);
315 ++val;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500316
Davide Pesavento484bbe52017-02-15 00:03:46 -0500317 m_routes.clear();
Vince Lehmandbf3f702014-07-15 13:00:43 -0500318 for (; val != m_wire.elements_end(); ++val) {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500319 if (val->type() != tlv::nfd::Route) {
320 BOOST_THROW_EXCEPTION(Error("expecting Route, but Block has type " + to_string(val->type())));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500321 }
Davide Pesavento484bbe52017-02-15 00:03:46 -0500322 m_routes.emplace_back(*val);
Vince Lehmandbf3f702014-07-15 13:00:43 -0500323 }
324}
325
Davide Pesavento484bbe52017-02-15 00:03:46 -0500326bool
327operator==(const RibEntry& a, const RibEntry& b)
328{
329 const auto& aRoutes = a.getRoutes();
330 const auto& bRoutes = b.getRoutes();
331
332 if (a.getName() != b.getName() ||
333 aRoutes.size() != bRoutes.size())
334 return false;
335
336 std::vector<bool> matched(bRoutes.size(), false);
337 return std::all_of(aRoutes.begin(), aRoutes.end(),
338 [&] (const Route& route) {
339 for (size_t i = 0; i < bRoutes.size(); ++i) {
340 if (!matched[i] && bRoutes[i] == route) {
341 matched[i] = true;
342 return true;
343 }
344 }
345 return false;
346 });
347}
348
Vince Lehmandbf3f702014-07-15 13:00:43 -0500349std::ostream&
350operator<<(std::ostream& os, const RibEntry& entry)
351{
Davide Pesavento484bbe52017-02-15 00:03:46 -0500352 os << "RibEntry(Prefix: " << entry.getName() << ",\n"
353 << " Routes: [";
Vince Lehmandbf3f702014-07-15 13:00:43 -0500354
Davide Pesavento484bbe52017-02-15 00:03:46 -0500355 bool isFirst = true;
356 for (const auto& route : entry.getRoutes()) {
357 if (!isFirst)
358 os << ",\n ";
359 isFirst = false;
360 os << route;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500361 }
Davide Pesavento484bbe52017-02-15 00:03:46 -0500362 os << "]\n";
Vince Lehmandbf3f702014-07-15 13:00:43 -0500363
Davide Pesavento484bbe52017-02-15 00:03:46 -0500364 return os << " )";
Vince Lehmandbf3f702014-07-15 13:00:43 -0500365}
366
367} // namespace nfd
368} // namespace ndn