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