blob: c4c2d82fed9d46ce70da58e24b247f8cf854d439 [file] [log] [blame]
Vince Lehmandbf3f702014-07-15 13:00:43 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shi5d75fd92017-08-08 18:09:20 +00002/*
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
Davide Pesavento88a0d812017-08-19 21:31:42 -0400121NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Route);
Vince Lehmandbf3f702014-07-15 13:00:43 -0500122
123const Block&
124Route::wireEncode() const
125{
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500126 if (m_wire.hasWire())
Vince Lehmandbf3f702014-07-15 13:00:43 -0500127 return m_wire;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500128
129 EncodingEstimator estimator;
130 size_t estimatedSize = wireEncode(estimator);
131
132 EncodingBuffer buffer(estimatedSize, 0);
133 wireEncode(buffer);
134
135 m_wire = buffer.block();
Vince Lehmandbf3f702014-07-15 13:00:43 -0500136 return m_wire;
137}
138
139void
Davide Pesavento484bbe52017-02-15 00:03:46 -0500140Route::wireDecode(const Block& block)
Vince Lehmandbf3f702014-07-15 13:00:43 -0500141{
Davide Pesavento484bbe52017-02-15 00:03:46 -0500142 if (block.type() != tlv::nfd::Route) {
143 BOOST_THROW_EXCEPTION(Error("expecting Route, but Block has type " + to_string(block.type())));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500144 }
Davide Pesavento484bbe52017-02-15 00:03:46 -0500145 m_wire = block;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500146 m_wire.parse();
Vince Lehmandbf3f702014-07-15 13:00:43 -0500147 Block::element_const_iterator val = m_wire.elements_begin();
148
149 if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceId) {
150 m_faceId = readNonNegativeInteger(*val);
151 ++val;
152 }
153 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500154 BOOST_THROW_EXCEPTION(Error("missing required FaceId field"));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500155 }
156
157 if (val != m_wire.elements_end() && val->type() == tlv::nfd::Origin) {
Junxiao Shi5d75fd92017-08-08 18:09:20 +0000158 m_origin = readNonNegativeIntegerAs<RouteOrigin>(*val);
Vince Lehmandbf3f702014-07-15 13:00:43 -0500159 ++val;
160 }
161 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500162 BOOST_THROW_EXCEPTION(Error("missing required Origin field"));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500163 }
164
165 if (val != m_wire.elements_end() && val->type() == tlv::nfd::Cost) {
166 m_cost = readNonNegativeInteger(*val);
167 ++val;
168 }
169 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500170 BOOST_THROW_EXCEPTION(Error("missing required Cost field"));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500171 }
172
173 if (val != m_wire.elements_end() && val->type() == tlv::nfd::Flags) {
174 m_flags = readNonNegativeInteger(*val);
175 ++val;
176 }
177 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500178 BOOST_THROW_EXCEPTION(Error("missing required Flags field"));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500179 }
180
181 if (val != m_wire.elements_end() && val->type() == tlv::nfd::ExpirationPeriod) {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500182 m_expirationPeriod.emplace(readNonNegativeInteger(*val));
183 ++val;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500184 }
185 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500186 m_expirationPeriod = nullopt;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500187 }
188}
189
Davide Pesavento484bbe52017-02-15 00:03:46 -0500190bool
191operator==(const Route& a, const Route& b)
192{
193 return a.getFaceId() == b.getFaceId() &&
194 a.getOrigin() == b.getOrigin() &&
195 a.getCost() == b.getCost() &&
196 a.getFlags() == b.getFlags() &&
197 a.getExpirationPeriod() == b.getExpirationPeriod();
198}
199
Vince Lehmandbf3f702014-07-15 13:00:43 -0500200std::ostream&
201operator<<(std::ostream& os, const Route& route)
202{
203 os << "Route("
204 << "FaceId: " << route.getFaceId() << ", "
205 << "Origin: " << route.getOrigin() << ", "
Davide Pesaventoe78eeca2017-02-23 23:22:32 -0500206 << "Cost: " << route.getCost() << ", "
207 << "Flags: " << AsHex{route.getFlags()} << ", ";
Davide Pesavento484bbe52017-02-15 00:03:46 -0500208
209 if (route.hasExpirationPeriod()) {
Vince Lehmandbf3f702014-07-15 13:00:43 -0500210 os << "ExpirationPeriod: " << route.getExpirationPeriod();
211 }
212 else {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500213 os << "ExpirationPeriod: infinite";
Vince Lehmandbf3f702014-07-15 13:00:43 -0500214 }
215
Davide Pesavento484bbe52017-02-15 00:03:46 -0500216 return os << ")";
Vince Lehmandbf3f702014-07-15 13:00:43 -0500217}
218
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500219////////////////////
Vince Lehmandbf3f702014-07-15 13:00:43 -0500220
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500221RibEntry::RibEntry() = default;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500222
223RibEntry::RibEntry(const Block& block)
224{
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500225 this->wireDecode(block);
Vince Lehmandbf3f702014-07-15 13:00:43 -0500226}
227
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500228RibEntry&
229RibEntry::setName(const Name& prefix)
230{
231 m_prefix = prefix;
232 m_wire.reset();
233 return *this;
234}
235
236RibEntry&
237RibEntry::addRoute(const Route& route)
238{
239 m_routes.push_back(route);
240 m_wire.reset();
241 return *this;
242}
243
244RibEntry&
245RibEntry::clearRoutes()
246{
247 m_routes.clear();
248 m_wire.reset();
249 return *this;
250}
Vince Lehmandbf3f702014-07-15 13:00:43 -0500251
Alexander Afanasyev74633892015-02-08 18:08:46 -0800252template<encoding::Tag TAG>
Vince Lehmandbf3f702014-07-15 13:00:43 -0500253size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -0800254RibEntry::wireEncode(EncodingImpl<TAG>& block) const
Vince Lehmandbf3f702014-07-15 13:00:43 -0500255{
256 size_t totalLength = 0;
257
Davide Pesavento484bbe52017-02-15 00:03:46 -0500258 for (const auto& route : m_routes | boost::adaptors::reversed) {
259 totalLength += route.wireEncode(block);
260 }
Vince Lehmandbf3f702014-07-15 13:00:43 -0500261 totalLength += m_prefix.wireEncode(block);
262
263 totalLength += block.prependVarNumber(totalLength);
264 totalLength += block.prependVarNumber(tlv::nfd::RibEntry);
Vince Lehmandbf3f702014-07-15 13:00:43 -0500265 return totalLength;
266}
267
Davide Pesavento88a0d812017-08-19 21:31:42 -0400268NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(RibEntry);
Vince Lehmandbf3f702014-07-15 13:00:43 -0500269
270const Block&
271RibEntry::wireEncode() const
272{
Davide Pesavento6ad3d532017-02-17 01:43:57 -0500273 if (m_wire.hasWire())
Vince Lehmandbf3f702014-07-15 13:00:43 -0500274 return m_wire;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500275
276 EncodingEstimator estimator;
277 size_t estimatedSize = wireEncode(estimator);
278
279 EncodingBuffer buffer(estimatedSize, 0);
280 wireEncode(buffer);
281
282 m_wire = buffer.block();
Vince Lehmandbf3f702014-07-15 13:00:43 -0500283 return m_wire;
284}
285
286void
Davide Pesavento484bbe52017-02-15 00:03:46 -0500287RibEntry::wireDecode(const Block& block)
Vince Lehmandbf3f702014-07-15 13:00:43 -0500288{
Davide Pesavento484bbe52017-02-15 00:03:46 -0500289 if (block.type() != tlv::nfd::RibEntry) {
290 BOOST_THROW_EXCEPTION(Error("expecting RibEntry, but Block has type " + to_string(block.type())));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500291 }
Davide Pesavento484bbe52017-02-15 00:03:46 -0500292 m_wire = block;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500293 m_wire.parse();
Vince Lehmandbf3f702014-07-15 13:00:43 -0500294 Block::element_const_iterator val = m_wire.elements_begin();
295
Davide Pesavento484bbe52017-02-15 00:03:46 -0500296 if (val == m_wire.elements_end()) {
297 BOOST_THROW_EXCEPTION(Error("unexpected end of RibEntry"));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500298 }
Davide Pesavento484bbe52017-02-15 00:03:46 -0500299 else if (val->type() != tlv::Name) {
300 BOOST_THROW_EXCEPTION(Error("expecting Name, but Block has type " + to_string(val->type())));
Vince Lehmandbf3f702014-07-15 13:00:43 -0500301 }
Davide Pesavento484bbe52017-02-15 00:03:46 -0500302 m_prefix.wireDecode(*val);
303 ++val;
Vince Lehmandbf3f702014-07-15 13:00:43 -0500304
Davide Pesavento484bbe52017-02-15 00:03:46 -0500305 m_routes.clear();
Vince Lehmandbf3f702014-07-15 13:00:43 -0500306 for (; val != m_wire.elements_end(); ++val) {
Davide Pesavento484bbe52017-02-15 00:03:46 -0500307 if (val->type() != tlv::nfd::Route) {
308 BOOST_THROW_EXCEPTION(Error("expecting Route, 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_routes.emplace_back(*val);
Vince Lehmandbf3f702014-07-15 13:00:43 -0500311 }
312}
313
Davide Pesavento484bbe52017-02-15 00:03:46 -0500314bool
315operator==(const RibEntry& a, const RibEntry& b)
316{
317 const auto& aRoutes = a.getRoutes();
318 const auto& bRoutes = b.getRoutes();
319
320 if (a.getName() != b.getName() ||
321 aRoutes.size() != bRoutes.size())
322 return false;
323
324 std::vector<bool> matched(bRoutes.size(), false);
325 return std::all_of(aRoutes.begin(), aRoutes.end(),
326 [&] (const Route& route) {
327 for (size_t i = 0; i < bRoutes.size(); ++i) {
328 if (!matched[i] && bRoutes[i] == route) {
329 matched[i] = true;
330 return true;
331 }
332 }
333 return false;
334 });
335}
336
Vince Lehmandbf3f702014-07-15 13:00:43 -0500337std::ostream&
338operator<<(std::ostream& os, const RibEntry& entry)
339{
Davide Pesavento484bbe52017-02-15 00:03:46 -0500340 os << "RibEntry(Prefix: " << entry.getName() << ",\n"
341 << " Routes: [";
Vince Lehmandbf3f702014-07-15 13:00:43 -0500342
Davide Pesaventocf415762017-02-25 23:46:47 -0500343 std::copy(entry.getRoutes().begin(), entry.getRoutes().end(),
344 make_ostream_joiner(os, ",\n "));
345
Davide Pesavento484bbe52017-02-15 00:03:46 -0500346 os << "]\n";
Vince Lehmandbf3f702014-07-15 13:00:43 -0500347
Davide Pesavento484bbe52017-02-15 00:03:46 -0500348 return os << " )";
Vince Lehmandbf3f702014-07-15 13:00:43 -0500349}
350
351} // namespace nfd
352} // namespace ndn