blob: d2472fb5aee9f5f825d28f642bcdb630256c2fcf [file] [log] [blame]
Weiqi Shi28a90fb2014-07-09 10:28:55 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014, Regents of the University of California.
4 *
5 * This file is part of NDN repo-ng (Next generation of NDN repository).
6 * See AUTHORS.md for complete list of repo-ng authors and contributors.
7 *
8 * repo-ng is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * repo-ng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * repo-ng, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "index.hpp"
21#include "skiplist.hpp"
22
23#include <ndn-cxx/util/crypto.hpp>
24#include "ndn-cxx/security/signature-sha256-with-rsa.hpp"
25
26namespace repo {
27
28/** @brief determines if entry can satisfy interest
29 * @param hash SHA256 hash of PublisherPublicKeyLocator if exists in interest, otherwise ignored
30 */
31static bool
32matchesSimpleSelectors(const Interest& interest, ndn::ConstBufferPtr& hash,
33 const Index::Entry& entry)
34{
35 const Name& fullName = entry.getName();
36
37 if (!interest.getName().isPrefixOf(fullName))
38 return false;
39
40 size_t nSuffixComponents = fullName.size() - interest.getName().size();
41 if (interest.getMinSuffixComponents() >= 0 &&
42 nSuffixComponents < static_cast<size_t>(interest.getMinSuffixComponents()))
43 return false;
44 if (interest.getMaxSuffixComponents() >= 0 &&
45 nSuffixComponents > static_cast<size_t>(interest.getMaxSuffixComponents()))
46 return false;
47
48 if (!interest.getExclude().empty() &&
49 entry.getName().size() > interest.getName().size() &&
50 interest.getExclude().isExcluded(entry.getName()[interest.getName().size()]))
51 return false;
52 if (!interest.getPublisherPublicKeyLocator().empty())
53 {
54 if (*entry.getKeyLocatorHash() != *hash)
55 return false;
56 }
57 return true;
58}
59
60Index::Index(const size_t nMaxPackets)
61 : m_maxPackets(nMaxPackets)
62 , m_size(0)
63{
64}
65
66
67bool
68Index::insert(const Data& data, const int64_t id)
69{
70 if (isFull())
71 throw Error("The Index is Full. Cannot Insert Any Data!");
72 Entry entry(data, id);
73 bool isInserted = m_skipList.insert(entry).second;
74 if (isInserted)
75 ++m_size;
76 return isInserted;
77}
78
79bool
80Index::insert(const Name& fullName, const int64_t id,
81 const ndn::ConstBufferPtr& keyLocatorHash)
82{
83 if (isFull())
84 throw Error("The Index is Full. Cannot Insert Any Data!");
85 Entry entry(fullName, keyLocatorHash, id);
86 bool isInserted = m_skipList.insert(entry).second;
87 if (isInserted)
88 ++m_size;
89 return isInserted;
90}
91
92std::pair<int64_t,Name>
93Index::find(const Interest& interest) const
94{
95 Name name = interest.getName();
96 IndexSkipList::const_iterator result = m_skipList.lower_bound(name);
97 if (result != m_skipList.end())
98 {
99 return selectChild(interest, result);
100 }
101 else
102 {
103 return std::pair<int64_t,Name>();
104 }
105}
106
107std::pair<int64_t,Name>
108Index::find(const Name& name) const
109{
110 IndexSkipList::const_iterator result = m_skipList.lower_bound(name);
111 if (result != m_skipList.end())
112 {
113 return findFirstEntry(name, result);
114 }
115 else
116 {
117 return std::pair<int64_t,Name>();
118 }
119}
120
121bool
122Index::hasData(const Data& data) const
123{
124 Index::Entry entry(data, -1); // the id number is useless
125 IndexSkipList::const_iterator result = m_skipList.find(entry);
126 return result != m_skipList.end();
127
128}
129
130std::pair<int64_t,Name>
131Index::findFirstEntry(const Name& prefix,
132 IndexSkipList::const_iterator startingPoint) const
133{
134 BOOST_ASSERT(startingPoint != m_skipList.end());
135 if (prefix.isPrefixOf(startingPoint->getName()))
136 {
137 return std::make_pair(startingPoint->getId(), startingPoint->getName());
138 }
139 else
140 {
141 return std::pair<int64_t,Name>();
142 }
143}
144
145bool
146Index::erase(const Name& fullName)
147{
148 Entry entry(fullName);
149 IndexSkipList::const_iterator findIterator = m_skipList.find(entry);
150 if (findIterator != m_skipList.end())
151 {
152 m_skipList.erase(findIterator);
153 m_size--;
154 return true;
155 }
156 else
157 return false;
158}
159
160const ndn::ConstBufferPtr
161Index::computeKeyLocatorHash(const KeyLocator& keyLocator)
162{
163 const Block& block = keyLocator.wireEncode();
164 ndn::ConstBufferPtr keyLocatorHash = ndn::crypto::sha256(block.wire(), block.size());
165 return keyLocatorHash;
166}
167
168std::pair<int64_t,Name>
169Index::selectChild(const Interest& interest,
170 IndexSkipList::const_iterator startingPoint) const
171{
172 BOOST_ASSERT(startingPoint != m_skipList.end());
173 bool isLeftmost = (interest.getChildSelector() <= 0);
174 ndn::ConstBufferPtr hash;
175 if (!interest.getPublisherPublicKeyLocator().empty())
176 {
177 KeyLocator keyLocator = interest.getPublisherPublicKeyLocator();
178 const Block& block = keyLocator.wireEncode();
179 hash = ndn::crypto::sha256(block.wire(), block.size());
180 }
181
182 if (isLeftmost)
183 {
184 for (IndexSkipList::const_iterator it = startingPoint;
185 it != m_skipList.end(); ++it)
186 {
187 if (!interest.getName().isPrefixOf(it->getName()))
188 return std::pair<int64_t,Name>();
189 if (matchesSimpleSelectors(interest, hash, (*it)))
190 return std::make_pair(it->getId(), it->getName());
191 }
192 }
193 else
194 {
195 IndexSkipList::const_iterator boundary = m_skipList.lower_bound(interest.getName());
196 if (boundary == m_skipList.end() || !interest.getName().isPrefixOf(boundary->getName()))
197 return std::pair<int64_t,Name>();
198 Name successor = interest.getName().getSuccessor();
199 IndexSkipList::const_iterator last = interest.getName().size() == 0 ?
200 m_skipList.end() : m_skipList.lower_bound(interest.getName().getSuccessor());
201 while (true)
202 {
203 IndexSkipList::const_iterator prev = last;
204 --prev;
205 if (prev == boundary)
206 {
207 bool isMatch = matchesSimpleSelectors(interest, hash, (*prev));
208 if (isMatch)
209 {
210 return std::make_pair(prev->getId(), prev->getName());
211 }
212 else
213 return std::pair<int64_t,Name>();
214 }
215 IndexSkipList::const_iterator first =
216 m_skipList.lower_bound(prev->getName().getPrefix(interest.getName().size() + 1));
217 IndexSkipList::const_iterator match =
218 std::find_if(first, last, bind(&matchesSimpleSelectors, interest, hash, _1));
219 if (match != last)
220 {
221 return std::make_pair(match->getId(), match->getName());
222 }
223 last = first;
224 }
225 }
226 return std::pair<int64_t,Name>();
227}
228
229Index::Entry::Entry(const Data& data, const int64_t id)
230 : m_name(data.getFullName())
231 , m_id(id)
232{
233 const ndn::Signature& signature = data.getSignature();
234 if (signature.hasKeyLocator())
235 m_keyLocatorHash = computeKeyLocatorHash(signature.getKeyLocator());
236}
237
238Index::Entry::Entry(const Name& fullName, const KeyLocator& keyLocator, const int64_t id)
239 : m_name(fullName)
240 , m_keyLocatorHash(computeKeyLocatorHash(keyLocator))
241 , m_id(id)
242{
243}
244
245Index::Entry::Entry(const Name& fullName,
246 const ndn::ConstBufferPtr& keyLocatorHash, const int64_t id)
247 : m_name(fullName)
248 , m_keyLocatorHash(keyLocatorHash)
249 , m_id(id)
250{
251}
252
253Index::Entry::Entry(const Name& name)
254 : m_name(name)
255{
256}
257
258} // namespace repo