blob: 619fd5e46799ff83bb4a05e8a6e435d3d6ec28c6 [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"
Davide Pesaventoe78eeca2017-02-23 23:22:32 -050027#include "util/string-helper.hpp"
Vince Lehmandbf3f702014-07-15 13:00:43 -050028
Davide Pesavento484bbe52017-02-15 00:03:46 -050029#include <boost/range/adaptor/reversed.hpp>
30
Vince Lehmandbf3f702014-07-15 13:00:43 -050031namespace ndn {
32namespace nfd {
33
Davide Pesavento484bbe52017-02-15 00:03:46 -050034BOOST_CONCEPT_ASSERT((StatusDatasetItem<Route>));
35BOOST_CONCEPT_ASSERT((StatusDatasetItem<RibEntry>));
Vince Lehmandbf3f702014-07-15 13:00:43 -050036
37Route::Route()
Davide Pesaventof8503d22017-02-17 01:19:10 -050038 : m_faceId(INVALID_FACE_ID)
Davide Pesaventoe8e48c22017-04-13 00:35:33 -040039 , m_origin(ROUTE_ORIGIN_APP)
Vince Lehmandbf3f702014-07-15 13:00:43 -050040 , m_cost(0)
41 , m_flags(ROUTE_FLAG_CHILD_INHERIT)
Vince Lehmandbf3f702014-07-15 13:00:43 -050042{
43}
44
45Route::Route(const Block& block)
46{
Davide Pesavento6ad3d532017-02-17 01:43:57 -050047 this->wireDecode(block);
48}
49
50Route&
51Route::setFaceId(uint64_t faceId)
52{
53 m_faceId = faceId;
54 m_wire.reset();
55 return *this;
56}
57
58Route&
Davide Pesaventoe8e48c22017-04-13 00:35:33 -040059Route::setOrigin(RouteOrigin origin)
Davide Pesavento6ad3d532017-02-17 01:43:57 -050060{
61 m_origin = origin;
62 m_wire.reset();
63 return *this;
64}
65
66Route&
67Route::setCost(uint64_t cost)
68{
69 m_cost = cost;
70 m_wire.reset();
71 return *this;
72}
73
74Route&
75Route::setFlags(uint64_t flags)
76{
77 m_flags = flags;
78 m_wire.reset();
79 return *this;
80}
81
82Route&
83Route::setExpirationPeriod(time::milliseconds expirationPeriod)
84{
Davide Pesavento484bbe52017-02-15 00:03:46 -050085 if (expirationPeriod == time::milliseconds::max())
86 return unsetExpirationPeriod();
87
Davide Pesavento6ad3d532017-02-17 01:43:57 -050088 m_expirationPeriod = expirationPeriod;
Davide Pesavento484bbe52017-02-15 00:03:46 -050089 m_wire.reset();
90 return *this;
91}
92
93Route&
94Route::unsetExpirationPeriod()
95{
96 m_expirationPeriod = nullopt;
Davide Pesavento6ad3d532017-02-17 01:43:57 -050097 m_wire.reset();
98 return *this;
Vince Lehmandbf3f702014-07-15 13:00:43 -050099}
100
Alexander Afanasyev74633892015-02-08 18:08:46 -0800101template<encoding::Tag TAG>
Vince Lehmandbf3f702014-07-15 13:00:43 -0500102size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800103Route::wireEncode(EncodingImpl<TAG>& block) const
Vince Lehmandbf3f702014-07-15 13:00:43 -0500104{
105 size_t totalLength = 0;
106
Davide Pesavento484bbe52017-02-15 00:03:46 -0500107 if (m_expirationPeriod) {
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500108 totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::ExpirationPeriod,
Davide Pesavento484bbe52017-02-15 00:03:46 -0500109 static_cast<uint64_t>(m_expirationPeriod->count()));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500110 }
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500111 totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::Flags, m_flags);
112 totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::Cost, m_cost);
113 totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::Origin, m_origin);
114 totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::FaceId, m_faceId);
Vince Lehmandbf3f702014-07-15 13:00:43 -0500115
116 totalLength += block.prependVarNumber(totalLength);
117 totalLength += block.prependVarNumber(ndn::tlv::nfd::Route);
Vince Lehmandbf3f702014-07-15 13:00:43 -0500118 return totalLength;
119}
120
121template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800122Route::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& block) const;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500123
124template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800125Route::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& block) const;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500126
127const Block&
128Route::wireEncode() const
129{
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500130 if (m_wire.hasWire())
Vince Lehmandbf3f702014-07-15 13:00:43 -0500131 return m_wire;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500132
133 EncodingEstimator estimator;
134 size_t estimatedSize = wireEncode(estimator);
135
136 EncodingBuffer buffer(estimatedSize, 0);
137 wireEncode(buffer);
138
139 m_wire = buffer.block();
Vince Lehmandbf3f702014-07-15 13:00:43 -0500140 return m_wire;
141}
142
143void
Davide Pesavento484bbe52017-02-15 00:03:46 -0500144Route::wireDecode(const Block& block)
Vince Lehmandbf3f702014-07-15 13:00:43 -0500145{
Davide Pesavento484bbe52017-02-15 00:03:46 -0500146 if (block.type() != tlv::nfd::Route) {
147 BOOST_THROW_EXCEPTION(Error("expecting Route, but Block has type " + to_string(block.type())));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500148 }
Davide Pesavento484bbe52017-02-15 00:03:46 -0500149 m_wire = block;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500150 m_wire.parse();
Vince Lehmandbf3f702014-07-15 13:00:43 -0500151 Block::element_const_iterator val = m_wire.elements_begin();
152
153 if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceId) {
154 m_faceId = readNonNegativeInteger(*val);
155 ++val;
156 }
157 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500158 BOOST_THROW_EXCEPTION(Error("missing required FaceId field"));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500159 }
160
161 if (val != m_wire.elements_end() && val->type() == tlv::nfd::Origin) {
Davide Pesaventoe8e48c22017-04-13 00:35:33 -0400162 m_origin = static_cast<RouteOrigin>(readNonNegativeInteger(*val));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500163 ++val;
164 }
165 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500166 BOOST_THROW_EXCEPTION(Error("missing required Origin field"));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500167 }
168
169 if (val != m_wire.elements_end() && val->type() == tlv::nfd::Cost) {
170 m_cost = readNonNegativeInteger(*val);
171 ++val;
172 }
173 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500174 BOOST_THROW_EXCEPTION(Error("missing required Cost field"));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500175 }
176
177 if (val != m_wire.elements_end() && val->type() == tlv::nfd::Flags) {
178 m_flags = readNonNegativeInteger(*val);
179 ++val;
180 }
181 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500182 BOOST_THROW_EXCEPTION(Error("missing required Flags field"));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500183 }
184
185 if (val != m_wire.elements_end() && val->type() == tlv::nfd::ExpirationPeriod) {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500186 m_expirationPeriod.emplace(readNonNegativeInteger(*val));
187 ++val;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500188 }
189 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500190 m_expirationPeriod = nullopt;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500191 }
192}
193
Davide Pesavento484bbe52017-02-15 00:03:46 -0500194bool
195operator==(const Route& a, const Route& b)
196{
197 return a.getFaceId() == b.getFaceId() &&
198 a.getOrigin() == b.getOrigin() &&
199 a.getCost() == b.getCost() &&
200 a.getFlags() == b.getFlags() &&
201 a.getExpirationPeriod() == b.getExpirationPeriod();
202}
203
Vince Lehmandbf3f702014-07-15 13:00:43 -0500204std::ostream&
205operator<<(std::ostream& os, const Route& route)
206{
207 os << "Route("
208 << "FaceId: " << route.getFaceId() << ", "
209 << "Origin: " << route.getOrigin() << ", "
Davide Pesaventoe78eeca2017-02-23 23:22:32 -0500210 << "Cost: " << route.getCost() << ", "
211 << "Flags: " << AsHex{route.getFlags()} << ", ";
Davide Pesavento484bbe52017-02-15 00:03:46 -0500212
213 if (route.hasExpirationPeriod()) {
Vince Lehmandbf3f702014-07-15 13:00:43 -0500214 os << "ExpirationPeriod: " << route.getExpirationPeriod();
215 }
216 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500217 os << "ExpirationPeriod: infinite";
Vince Lehmandbf3f702014-07-15 13:00:43 -0500218 }
219
Davide Pesavento484bbe52017-02-15 00:03:46 -0500220 return os << ")";
Vince Lehmandbf3f702014-07-15 13:00:43 -0500221}
222
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500223////////////////////
Vince Lehmandbf3f702014-07-15 13:00:43 -0500224
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500225RibEntry::RibEntry() = default;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500226
227RibEntry::RibEntry(const Block& block)
228{
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500229 this->wireDecode(block);
Vince Lehmandbf3f702014-07-15 13:00:43 -0500230}
231
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500232RibEntry&
233RibEntry::setName(const Name& prefix)
234{
235 m_prefix = prefix;
236 m_wire.reset();
237 return *this;
238}
239
240RibEntry&
241RibEntry::addRoute(const Route& route)
242{
243 m_routes.push_back(route);
244 m_wire.reset();
245 return *this;
246}
247
248RibEntry&
249RibEntry::clearRoutes()
250{
251 m_routes.clear();
252 m_wire.reset();
253 return *this;
254}
Vince Lehmandbf3f702014-07-15 13:00:43 -0500255
Alexander Afanasyev74633892015-02-08 18:08:46 -0800256template<encoding::Tag TAG>
Vince Lehmandbf3f702014-07-15 13:00:43 -0500257size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800258RibEntry::wireEncode(EncodingImpl<TAG>& block) const
Vince Lehmandbf3f702014-07-15 13:00:43 -0500259{
260 size_t totalLength = 0;
261
Davide Pesavento484bbe52017-02-15 00:03:46 -0500262 for (const auto& route : m_routes | boost::adaptors::reversed) {
263 totalLength += route.wireEncode(block);
264 }
Vince Lehmandbf3f702014-07-15 13:00:43 -0500265 totalLength += m_prefix.wireEncode(block);
266
267 totalLength += block.prependVarNumber(totalLength);
268 totalLength += block.prependVarNumber(tlv::nfd::RibEntry);
Vince Lehmandbf3f702014-07-15 13:00:43 -0500269 return totalLength;
270}
271
272template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800273RibEntry::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& block) const;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500274
275template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800276RibEntry::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& block) const;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500277
278const Block&
279RibEntry::wireEncode() const
280{
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500281 if (m_wire.hasWire())
Vince Lehmandbf3f702014-07-15 13:00:43 -0500282 return m_wire;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500283
284 EncodingEstimator estimator;
285 size_t estimatedSize = wireEncode(estimator);
286
287 EncodingBuffer buffer(estimatedSize, 0);
288 wireEncode(buffer);
289
290 m_wire = buffer.block();
Vince Lehmandbf3f702014-07-15 13:00:43 -0500291 return m_wire;
292}
293
294void
Davide Pesavento484bbe52017-02-15 00:03:46 -0500295RibEntry::wireDecode(const Block& block)
Vince Lehmandbf3f702014-07-15 13:00:43 -0500296{
Davide Pesavento484bbe52017-02-15 00:03:46 -0500297 if (block.type() != tlv::nfd::RibEntry) {
298 BOOST_THROW_EXCEPTION(Error("expecting RibEntry, but Block has type " + to_string(block.type())));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500299 }
Davide Pesavento484bbe52017-02-15 00:03:46 -0500300 m_wire = block;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500301 m_wire.parse();
Vince Lehmandbf3f702014-07-15 13:00:43 -0500302 Block::element_const_iterator val = m_wire.elements_begin();
303
Davide Pesavento484bbe52017-02-15 00:03:46 -0500304 if (val == m_wire.elements_end()) {
305 BOOST_THROW_EXCEPTION(Error("unexpected end of RibEntry"));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500306 }
Davide Pesavento484bbe52017-02-15 00:03:46 -0500307 else if (val->type() != tlv::Name) {
308 BOOST_THROW_EXCEPTION(Error("expecting Name, but Block has type " + to_string(val->type())));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500309 }
Davide Pesavento484bbe52017-02-15 00:03:46 -0500310 m_prefix.wireDecode(*val);
311 ++val;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500312
Davide Pesavento484bbe52017-02-15 00:03:46 -0500313 m_routes.clear();
Vince Lehmandbf3f702014-07-15 13:00:43 -0500314 for (; val != m_wire.elements_end(); ++val) {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500315 if (val->type() != tlv::nfd::Route) {
316 BOOST_THROW_EXCEPTION(Error("expecting Route, but Block has type " + to_string(val->type())));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500317 }
Davide Pesavento484bbe52017-02-15 00:03:46 -0500318 m_routes.emplace_back(*val);
Vince Lehmandbf3f702014-07-15 13:00:43 -0500319 }
320}
321
Davide Pesavento484bbe52017-02-15 00:03:46 -0500322bool
323operator==(const RibEntry& a, const RibEntry& b)
324{
325 const auto& aRoutes = a.getRoutes();
326 const auto& bRoutes = b.getRoutes();
327
328 if (a.getName() != b.getName() ||
329 aRoutes.size() != bRoutes.size())
330 return false;
331
332 std::vector<bool> matched(bRoutes.size(), false);
333 return std::all_of(aRoutes.begin(), aRoutes.end(),
334 [&] (const Route& route) {
335 for (size_t i = 0; i < bRoutes.size(); ++i) {
336 if (!matched[i] && bRoutes[i] == route) {
337 matched[i] = true;
338 return true;
339 }
340 }
341 return false;
342 });
343}
344
Vince Lehmandbf3f702014-07-15 13:00:43 -0500345std::ostream&
346operator<<(std::ostream& os, const RibEntry& entry)
347{
Davide Pesavento484bbe52017-02-15 00:03:46 -0500348 os << "RibEntry(Prefix: " << entry.getName() << ",\n"
349 << " Routes: [";
Vince Lehmandbf3f702014-07-15 13:00:43 -0500350
Davide Pesaventocf415762017-02-25 23:46:47 -0500351 std::copy(entry.getRoutes().begin(), entry.getRoutes().end(),
352 make_ostream_joiner(os, ",\n "));
353
Davide Pesavento484bbe52017-02-15 00:03:46 -0500354 os << "]\n";
Vince Lehmandbf3f702014-07-15 13:00:43 -0500355
Davide Pesavento484bbe52017-02-15 00:03:46 -0500356 return os << " )";
Vince Lehmandbf3f702014-07-15 13:00:43 -0500357}
358
359} // namespace nfd
360} // namespace ndn