blob: 5dbe5cd0765d7759c4b4753d66bb0a7820ae1f66 [file] [log] [blame]
Yanbiao Li8ee37ed2015-05-19 12:44:04 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev80b68e12015-09-17 17:01:04 -07003 * Copyright (c) 2013-2015 Regents of the University of California.
Yanbiao Li8ee37ed2015-05-19 12:44:04 -07004 *
Alexander Afanasyev80b68e12015-09-17 17:01:04 -07005 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Yanbiao Li8ee37ed2015-05-19 12:44:04 -07006 *
Alexander Afanasyev80b68e12015-09-17 17:01:04 -07007 * 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.
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070010 *
Alexander Afanasyev80b68e12015-09-17 17:01:04 -070011 * 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.
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070014 *
Alexander Afanasyev80b68e12015-09-17 17:01:04 -070015 * 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.
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070020 */
21
22#include "dispatcher.hpp"
23
24#include <algorithm>
25
26// #define NDN_CXX_MGMT_DISPATCHER_ENABLE_LOGGING
27
28namespace ndn {
29namespace mgmt {
30
31Authorization
32makeAcceptAllAuthorization()
33{
34 return [] (const Name& prefix,
35 const Interest& interest,
36 const ControlParameters* params,
Junxiao Shif65a3362015-09-06 20:54:54 -070037 const AcceptContinuation& accept,
38 const RejectContinuation& reject) {
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070039 accept("");
40 };
41}
42
43Dispatcher::Dispatcher(Face& face, security::KeyChain& keyChain,
44 const security::SigningInfo& signingInfo)
45 : m_face(face)
46 , m_keyChain(keyChain)
47 , m_signingInfo(signingInfo)
48{
49}
50
51Dispatcher::~Dispatcher()
52{
53 std::vector<Name> topPrefixNames;
54
55 std::transform(m_topLevelPrefixes.begin(),
56 m_topLevelPrefixes.end(),
57 std::back_inserter(topPrefixNames),
58 [] (const std::unordered_map<Name, TopPrefixEntry>::value_type& entry) {
59 return entry.second.topPrefix;
60 });
61
62 for (auto&& name : topPrefixNames) {
63 removeTopPrefix(name);
64 }
65}
66
67void
68Dispatcher::addTopPrefix(const Name& prefix,
69 bool wantRegister,
70 const security::SigningInfo& signingInfo)
71{
72 bool hasOverlap = std::any_of(m_topLevelPrefixes.begin(),
73 m_topLevelPrefixes.end(),
74 [&] (const std::unordered_map<Name, TopPrefixEntry>::value_type& x) {
75 return x.first.isPrefixOf(prefix) || prefix.isPrefixOf(x.first);
76 });
77 if (hasOverlap) {
78 BOOST_THROW_EXCEPTION(std::out_of_range("Top-level Prefixes overlapped"));
79 }
80
81 TopPrefixEntry& topPrefixEntry = m_topLevelPrefixes[prefix];;
82 topPrefixEntry.topPrefix = prefix;
83 topPrefixEntry.wantRegister = wantRegister;
84
85 if (wantRegister) {
86 RegisterPrefixFailureCallback failure = [] (const Name& name, const std::string& reason) {
87 BOOST_THROW_EXCEPTION(std::runtime_error(reason));
88 };
89 topPrefixEntry.registerPrefixId =
90 m_face.registerPrefix(prefix, bind([]{}), failure, signingInfo);
91 }
92
93 for (auto&& entry : m_handlers) {
94 Name fullPrefix = prefix;
95 fullPrefix.append(entry.first);
96
97 const InterestFilterId* interestFilterId =
98 m_face.setInterestFilter(fullPrefix, std::bind(entry.second, prefix, _2));
99
100 topPrefixEntry.interestFilters.push_back(interestFilterId);
101 }
102}
103
104void
105Dispatcher::removeTopPrefix(const Name& prefix)
106{
107 auto it = m_topLevelPrefixes.find(prefix);
108 if (it == m_topLevelPrefixes.end()) {
109 return;
110 }
111
112 const TopPrefixEntry& topPrefixEntry = it->second;
113 if (topPrefixEntry.wantRegister) {
114 m_face.unregisterPrefix(topPrefixEntry.registerPrefixId, bind([]{}), bind([]{}));
115 }
116
117 for (auto&& filter : topPrefixEntry.interestFilters) {
118 m_face.unsetInterestFilter(filter);
119 }
120
121 m_topLevelPrefixes.erase(it);
122}
123
124bool
125Dispatcher::isOverlappedWithOthers(const PartialName& relPrefix)
126{
127 bool hasOverlapWithHandlers =
128 std::any_of(m_handlers.begin(), m_handlers.end(),
129 [&] (const HandlerMap::value_type& entry) {
130 return entry.first.isPrefixOf(relPrefix) || relPrefix.isPrefixOf(entry.first);
131 });
132 bool hasOverlapWithStreams =
133 std::any_of(m_streams.begin(), m_streams.end(),
134 [&] (const std::unordered_map<PartialName, uint64_t>::value_type& entry) {
135 return entry.first.isPrefixOf(relPrefix) || relPrefix.isPrefixOf(entry.first);
136 });
137
138 return hasOverlapWithHandlers || hasOverlapWithStreams;
139}
140
141void
142Dispatcher::afterAuthorizationRejected(RejectReply act, const Interest& interest)
143{
144 if (act == RejectReply::STATUS403) {
145 sendControlResponse(ControlResponse(403, "authorization rejected"), interest);
146 }
147}
148
149void
150Dispatcher::sendData(const Name& dataName, const Block& content,
151 const MetaInfo& metaInfo)
152{
153 shared_ptr<Data> data = make_shared<Data>(dataName);
154 data->setContent(content).setMetaInfo(metaInfo);
155
156 m_keyChain.sign(*data, m_signingInfo);
157
158 try {
159 m_face.put(*data);
160 }
161 catch (Face::Error& e) {
162#ifdef NDN_CXX_MGMT_DISPATCHER_ENABLE_LOGGING
163 std::clog << e.what() << std::endl;
164#endif // NDN_CXX_MGMT_DISPATCHER_ENABLE_LOGGING.
165 }
166}
167
168void
169Dispatcher::processControlCommandInterest(const Name& prefix,
170 const Name& relPrefix,
171 const Interest& interest,
172 const ControlParametersParser& parser,
173 const Authorization& authorization,
174 const AuthorizationAcceptedCallback& accepted,
175 const AuthorizationRejectedCallback& rejected)
176{
177 // /<prefix>/<relPrefix>/<parameters>
178 size_t parametersLoc = prefix.size() + relPrefix.size();
179 const name::Component& pc = interest.getName().get(parametersLoc);
180
181 shared_ptr<ControlParameters> parameters;
182 try {
183 parameters = parser(pc);
184 }
185 catch (tlv::Error& e) {
186 return;
187 }
188
189 AcceptContinuation accept = bind(accepted, _1, prefix, interest, parameters.get());
190 RejectContinuation reject = bind(rejected, _1, interest);
191 authorization(prefix, interest, parameters.get(), accept, reject);
192}
193
194void
195Dispatcher::processAuthorizedControlCommandInterest(const std::string& requester,
196 const Name& prefix,
197 const Interest& interest,
198 const ControlParameters* parameters,
199 const ValidateParameters& validateParams,
200 const ControlCommandHandler& handler)
201{
202 if (validateParams(*parameters)) {
203 handler(prefix, interest, *parameters,
204 bind(&Dispatcher::sendControlResponse, this, _1, interest, false));
205 }
206 else {
207 sendControlResponse(ControlResponse(400, "failed in validating parameters"), interest);
208 }
209}
210
211void
212Dispatcher::sendControlResponse(const ControlResponse& resp, const Interest& interest,
213 bool isNack/*= false*/)
214{
215 MetaInfo info;
216 if (isNack) {
217 info.setType(tlv::ContentType_Nack);
218 }
219
220 sendData(interest.getName(), resp.wireEncode(), info);
221}
222
223void
224Dispatcher::addStatusDataset(const PartialName& relPrefix,
Junxiao Shif65a3362015-09-06 20:54:54 -0700225 const Authorization& authorization,
226 const StatusDatasetHandler& handler)
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700227{
228 if (!m_topLevelPrefixes.empty()) {
229 BOOST_THROW_EXCEPTION(std::domain_error("one or more top-level prefix has been added"));
230 }
231
232 if (isOverlappedWithOthers(relPrefix)) {
233 BOOST_THROW_EXCEPTION(std::out_of_range("relPrefix overlapped"));
234 }
235
236 AuthorizationAcceptedCallback accepted =
237 bind(&Dispatcher::processAuthorizedStatusDatasetInterest, this,
238 _1, _2, _3, handler);
239 AuthorizationRejectedCallback rejected =
240 bind(&Dispatcher::afterAuthorizationRejected, this, _1, _2);
241 m_handlers[relPrefix] = bind(&Dispatcher::processStatusDatasetInterest, this,
242 _1, _2, authorization, accepted, rejected);
243}
244
245void
246Dispatcher::processStatusDatasetInterest(const Name& prefix,
247 const Interest& interest,
248 const Authorization& authorization,
249 const AuthorizationAcceptedCallback& accepted,
250 const AuthorizationRejectedCallback& rejected)
251{
252 const Name& interestName = interest.getName();
253 bool endsWithVersionOrSegment = interestName.size() >= 1 &&
254 (interestName[-1].isVersion() || interestName[-1].isSegment());
255 if (endsWithVersionOrSegment) {
256 return;
257 }
258
259 AcceptContinuation accept = bind(accepted, _1, prefix, interest, nullptr);
260 RejectContinuation reject = bind(rejected, _1, interest);
261 authorization(prefix, interest, nullptr, accept, reject);
262}
263
264void
265Dispatcher::processAuthorizedStatusDatasetInterest(const std::string& requester,
266 const Name& prefix,
267 const Interest& interest,
268 const StatusDatasetHandler& handler)
269{
270 StatusDatasetContext context(interest, bind(&Dispatcher::sendData, this, _1, _2, _3));
271 handler(prefix, interest, context);
272}
273
274PostNotification
275Dispatcher::addNotificationStream(const PartialName& relPrefix)
276{
277 if (!m_topLevelPrefixes.empty()) {
278 throw std::domain_error("one or more top-level prefix has been added");
279 }
280
281 if (isOverlappedWithOthers(relPrefix)) {
282 throw std::out_of_range("relPrefix overlaps with another relPrefix");
283 }
284
285 m_streams[relPrefix] = 0;
286 return bind(&Dispatcher::postNotification, this, _1, relPrefix);
287}
288
289void
290Dispatcher::postNotification(const Block& notification, const PartialName& relPrefix)
291{
292 if (m_topLevelPrefixes.empty() || m_topLevelPrefixes.size() > 1) {
293#ifdef NDN_CXX_MGMT_DISPATCHER_ENABLE_LOGGING
294 std::clog << "no top-level prefix or too many top-level prefixes" << std::endl;
295#endif // NDN_CXX_MGMT_DISPATCHER_ENABLE_LOGGING.
296 return;
297 }
298
299 Name streamName(m_topLevelPrefixes.begin()->second.topPrefix);
300 streamName.append(relPrefix);
301 streamName.appendSequenceNumber(m_streams[streamName]++);
302 sendData(streamName, notification, MetaInfo());
303}
304
305} // namespace mgmt
306} // namespace ndn