blob: ebdb24576de657d73c211f885294d47089acbcc4 [file] [log] [blame]
Spyridon Mastorakis3b54e852015-04-07 08:03:25 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Davide Pesaventoe1789892017-02-26 15:50:52 -05003 * Copyright (c) 2013-2017 Regents of the University of California.
Spyridon Mastorakis3b54e852015-04-07 08:03:25 -07004 *
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
22#include "link.hpp"
23#include "interest.hpp"
24#include "encoding/block-helpers.hpp"
25#include "util/crypto.hpp"
26#include "security/key-chain.hpp"
Spyridon Mastorakis3b54e852015-04-07 08:03:25 -070027
Davide Pesaventoe1789892017-02-26 15:50:52 -050028#include <boost/range/adaptor/reversed.hpp>
Spyridon Mastorakis3b54e852015-04-07 08:03:25 -070029
30namespace ndn {
31
32BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Link>));
33BOOST_CONCEPT_ASSERT((WireEncodable<Link>));
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070034BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Link>));
Spyridon Mastorakis3b54e852015-04-07 08:03:25 -070035BOOST_CONCEPT_ASSERT((WireDecodable<Link>));
36static_assert(std::is_base_of<Data::Error, Link::Error>::value,
37 "Link::Error should inherit from Data::Error");
38
39Link::Link(const Block& block)
40{
41 wireDecode(block);
42}
43
44Link::Link(const Name& name)
45 : Data(name)
46{
47}
48
49Link::Link(const Name& name, std::initializer_list<std::pair<uint32_t, Name>> links)
50 : Data(name)
51{
52 m_delegations.insert(links);
53 encodeContent();
54}
55
56void
57Link::addDelegation(uint32_t preference, const Name& name)
58{
59 this->removeDelegationNoEncode(name);
60 m_delegations.insert({preference, name});
61 encodeContent();
62}
63
64bool
65Link::removeDelegation(const Name& name)
66{
67 bool hasRemovedDelegation = this->removeDelegationNoEncode(name);
68 if (hasRemovedDelegation) {
69 encodeContent();
70 }
71 return hasRemovedDelegation;
72}
73
74const Link::DelegationSet&
75Link::getDelegations() const
76{
77 return m_delegations;
78}
79
80template<encoding::Tag TAG>
81size_t
82Link::encodeContent(EncodingImpl<TAG>& encoder) const
83{
84 // LinkContent ::= CONTENT-TYPE TLV-LENGTH
85 // Delegation+
86
87 // Delegation ::= LINK-DELEGATION-TYPE TLV-LENGTH
88 // Preference
89 // Name
90
91 // Preference ::= LINK-PREFERENCE-TYPE TLV-LENGTH
92 // nonNegativeInteger
93
94 size_t totalLength = 0;
95 for (const auto& delegation : m_delegations | boost::adaptors::reversed) {
96 size_t delegationLength = 0;
97 delegationLength += std::get<1>(delegation).wireEncode(encoder);
98 delegationLength += prependNonNegativeIntegerBlock(encoder, tlv::LinkPreference,
99 std::get<0>(delegation));
100 delegationLength += encoder.prependVarNumber(delegationLength);
101 delegationLength += encoder.prependVarNumber(tlv::LinkDelegation);
102 totalLength += delegationLength;
103 }
104 totalLength += encoder.prependVarNumber(totalLength);
105 totalLength += encoder.prependVarNumber(tlv::Content);
106 return totalLength;
107}
108
109template size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700110Link::encodeContent<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& encoder) const;
Spyridon Mastorakis3b54e852015-04-07 08:03:25 -0700111
112template size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700113Link::encodeContent<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& encoder) const;
Spyridon Mastorakis3b54e852015-04-07 08:03:25 -0700114
115void
116Link::encodeContent()
117{
118 onChanged();
119
120 EncodingEstimator estimator;
121 size_t estimatedSize = encodeContent(estimator);
122
123 EncodingBuffer buffer(estimatedSize, 0);
124 encodeContent(buffer);
125
126 setContentType(tlv::ContentType_Link);
127 setContent(buffer.block());
128}
129
130void
131Link::decodeContent()
132{
133 // LinkContent ::= CONTENT-TYPE TLV-LENGTH
134 // Delegation+
135
136 // Delegation ::= LINK-DELEGATION-TYPE TLV-LENGTH
137 // Preference
138 // Name
139
140 // Preference ::= LINK-PREFERENCE-TYPE TLV-LENGTH
141 // nonNegativeInteger
142
143 if (getContentType() != tlv::ContentType_Link)
144 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700145 BOOST_THROW_EXCEPTION(Error("Expected Content Type Link"));
Spyridon Mastorakis3b54e852015-04-07 08:03:25 -0700146 }
147
148 const Block& content = getContent();
149 content.parse();
150
151 for (auto& delegation : content.elements()) {
152 delegation.parse();
153 Block::element_const_iterator val = delegation.elements_begin();
154 if (val == delegation.elements_end()) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700155 BOOST_THROW_EXCEPTION(Error("Unexpected Link Encoding"));
Spyridon Mastorakis3b54e852015-04-07 08:03:25 -0700156 }
157 uint32_t preference;
158 try {
159 preference = static_cast<uint32_t>(readNonNegativeInteger(*val));
160 }
Davide Pesaventoe1789892017-02-26 15:50:52 -0500161 catch (const tlv::Error&) {
Alexander Afanasyevcac08382015-09-02 14:52:40 -0700162 BOOST_THROW_EXCEPTION(Error("Missing Preference field in Link Encoding"));
Spyridon Mastorakis3b54e852015-04-07 08:03:25 -0700163 }
164 ++val;
165 if (val == delegation.elements_end()) {
Alexander Afanasyevcac08382015-09-02 14:52:40 -0700166 BOOST_THROW_EXCEPTION(Error("Missing Name field in Link Encoding"));
Spyridon Mastorakis3b54e852015-04-07 08:03:25 -0700167 }
168 Name name(*val);
169 m_delegations.insert({preference, name});
170 }
171}
172
173void
174Link::wireDecode(const Block& wire)
175{
176 Data::wireDecode(wire);
177 decodeContent();
178}
179
Spyridon Mastorakisc8188b32015-04-18 18:33:38 -0700180std::tuple<uint32_t, Name>
181Link::getDelegationFromWire(const Block& block, size_t index)
182{
183 block.parse();
184 const Block& contentBlock = block.get(tlv::Content);
185 contentBlock.parse();
186 const Block& delegationBlock = contentBlock.elements().at(index);
187 delegationBlock.parse();
188 if (delegationBlock.type() != tlv::LinkDelegation) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700189 BOOST_THROW_EXCEPTION(Error("Unexpected TLV-TYPE, expecting LinkDelegation"));
Spyridon Mastorakisc8188b32015-04-18 18:33:38 -0700190 }
191 return std::make_tuple(
192 static_cast<uint32_t>(
193 readNonNegativeInteger(delegationBlock.get(tlv::LinkPreference))),
194 Name(delegationBlock.get(tlv::Name)));
195}
196
197ssize_t
198Link::findDelegationFromWire(const Block& block, const Name& delegationName)
199{
200 block.parse();
201 const Block& contentBlock = block.get(tlv::Content);
202 contentBlock.parse();
203 size_t counter = 0;
204 for (auto&& delegationBlock : contentBlock.elements()) {
205 delegationBlock.parse();
206 if (delegationBlock.type() != tlv::LinkDelegation) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700207 BOOST_THROW_EXCEPTION(Error("Unexpected TLV-TYPE, expecting LinkDelegation"));
Spyridon Mastorakisc8188b32015-04-18 18:33:38 -0700208 }
209 Name name(delegationBlock.get(tlv::Name));
210 if (name == delegationName) {
211 return counter;
212 }
213 ++counter;
214 }
215 return INVALID_SELECTED_DELEGATION_INDEX;
216}
217
218ssize_t
219Link::countDelegationsFromWire(const Block& block)
220{
221 block.parse();
222 const Block& contentBlock = block.get(tlv::Content);
223 contentBlock.parse();
224 return contentBlock.elements_size();
225}
226
Spyridon Mastorakis3b54e852015-04-07 08:03:25 -0700227bool
228Link::removeDelegationNoEncode(const Name& name)
229{
230 bool hasRemoved = false;
231 auto i = m_delegations.begin();
232 while (i != m_delegations.end()) {
233 if (i->second == name) {
234 hasRemoved = true;
235 i = m_delegations.erase(i);
236 }
237 else {
238 ++i;
239 }
240 }
241 return hasRemoved;
242}
243
244} // namespace ndn