blob: b43334b34512ea475cfe9ca007d7d3e0828ee2ea [file] [log] [blame]
Yanbiao Li8ee37ed2015-05-19 12:44:04 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2015, Regents of the University of California,
4 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26#include "dispatcher.hpp"
27
28#include <algorithm>
29
30// #define NDN_CXX_MGMT_DISPATCHER_ENABLE_LOGGING
31
32namespace ndn {
33namespace mgmt {
34
35Authorization
36makeAcceptAllAuthorization()
37{
38 return [] (const Name& prefix,
39 const Interest& interest,
40 const ControlParameters* params,
41 AcceptContinuation accept,
42 RejectContinuation reject) {
43 accept("");
44 };
45}
46
47Dispatcher::Dispatcher(Face& face, security::KeyChain& keyChain,
48 const security::SigningInfo& signingInfo)
49 : m_face(face)
50 , m_keyChain(keyChain)
51 , m_signingInfo(signingInfo)
52{
53}
54
55Dispatcher::~Dispatcher()
56{
57 std::vector<Name> topPrefixNames;
58
59 std::transform(m_topLevelPrefixes.begin(),
60 m_topLevelPrefixes.end(),
61 std::back_inserter(topPrefixNames),
62 [] (const std::unordered_map<Name, TopPrefixEntry>::value_type& entry) {
63 return entry.second.topPrefix;
64 });
65
66 for (auto&& name : topPrefixNames) {
67 removeTopPrefix(name);
68 }
69}
70
71void
72Dispatcher::addTopPrefix(const Name& prefix,
73 bool wantRegister,
74 const security::SigningInfo& signingInfo)
75{
76 bool hasOverlap = std::any_of(m_topLevelPrefixes.begin(),
77 m_topLevelPrefixes.end(),
78 [&] (const std::unordered_map<Name, TopPrefixEntry>::value_type& x) {
79 return x.first.isPrefixOf(prefix) || prefix.isPrefixOf(x.first);
80 });
81 if (hasOverlap) {
82 BOOST_THROW_EXCEPTION(std::out_of_range("Top-level Prefixes overlapped"));
83 }
84
85 TopPrefixEntry& topPrefixEntry = m_topLevelPrefixes[prefix];;
86 topPrefixEntry.topPrefix = prefix;
87 topPrefixEntry.wantRegister = wantRegister;
88
89 if (wantRegister) {
90 RegisterPrefixFailureCallback failure = [] (const Name& name, const std::string& reason) {
91 BOOST_THROW_EXCEPTION(std::runtime_error(reason));
92 };
93 topPrefixEntry.registerPrefixId =
94 m_face.registerPrefix(prefix, bind([]{}), failure, signingInfo);
95 }
96
97 for (auto&& entry : m_handlers) {
98 Name fullPrefix = prefix;
99 fullPrefix.append(entry.first);
100
101 const InterestFilterId* interestFilterId =
102 m_face.setInterestFilter(fullPrefix, std::bind(entry.second, prefix, _2));
103
104 topPrefixEntry.interestFilters.push_back(interestFilterId);
105 }
106}
107
108void
109Dispatcher::removeTopPrefix(const Name& prefix)
110{
111 auto it = m_topLevelPrefixes.find(prefix);
112 if (it == m_topLevelPrefixes.end()) {
113 return;
114 }
115
116 const TopPrefixEntry& topPrefixEntry = it->second;
117 if (topPrefixEntry.wantRegister) {
118 m_face.unregisterPrefix(topPrefixEntry.registerPrefixId, bind([]{}), bind([]{}));
119 }
120
121 for (auto&& filter : topPrefixEntry.interestFilters) {
122 m_face.unsetInterestFilter(filter);
123 }
124
125 m_topLevelPrefixes.erase(it);
126}
127
128bool
129Dispatcher::isOverlappedWithOthers(const PartialName& relPrefix)
130{
131 bool hasOverlapWithHandlers =
132 std::any_of(m_handlers.begin(), m_handlers.end(),
133 [&] (const HandlerMap::value_type& entry) {
134 return entry.first.isPrefixOf(relPrefix) || relPrefix.isPrefixOf(entry.first);
135 });
136 bool hasOverlapWithStreams =
137 std::any_of(m_streams.begin(), m_streams.end(),
138 [&] (const std::unordered_map<PartialName, uint64_t>::value_type& entry) {
139 return entry.first.isPrefixOf(relPrefix) || relPrefix.isPrefixOf(entry.first);
140 });
141
142 return hasOverlapWithHandlers || hasOverlapWithStreams;
143}
144
145void
146Dispatcher::afterAuthorizationRejected(RejectReply act, const Interest& interest)
147{
148 if (act == RejectReply::STATUS403) {
149 sendControlResponse(ControlResponse(403, "authorization rejected"), interest);
150 }
151}
152
153void
154Dispatcher::sendData(const Name& dataName, const Block& content,
155 const MetaInfo& metaInfo)
156{
157 shared_ptr<Data> data = make_shared<Data>(dataName);
158 data->setContent(content).setMetaInfo(metaInfo);
159
160 m_keyChain.sign(*data, m_signingInfo);
161
162 try {
163 m_face.put(*data);
164 }
165 catch (Face::Error& e) {
166#ifdef NDN_CXX_MGMT_DISPATCHER_ENABLE_LOGGING
167 std::clog << e.what() << std::endl;
168#endif // NDN_CXX_MGMT_DISPATCHER_ENABLE_LOGGING.
169 }
170}
171
172void
173Dispatcher::processControlCommandInterest(const Name& prefix,
174 const Name& relPrefix,
175 const Interest& interest,
176 const ControlParametersParser& parser,
177 const Authorization& authorization,
178 const AuthorizationAcceptedCallback& accepted,
179 const AuthorizationRejectedCallback& rejected)
180{
181 // /<prefix>/<relPrefix>/<parameters>
182 size_t parametersLoc = prefix.size() + relPrefix.size();
183 const name::Component& pc = interest.getName().get(parametersLoc);
184
185 shared_ptr<ControlParameters> parameters;
186 try {
187 parameters = parser(pc);
188 }
189 catch (tlv::Error& e) {
190 return;
191 }
192
193 AcceptContinuation accept = bind(accepted, _1, prefix, interest, parameters.get());
194 RejectContinuation reject = bind(rejected, _1, interest);
195 authorization(prefix, interest, parameters.get(), accept, reject);
196}
197
198void
199Dispatcher::processAuthorizedControlCommandInterest(const std::string& requester,
200 const Name& prefix,
201 const Interest& interest,
202 const ControlParameters* parameters,
203 const ValidateParameters& validateParams,
204 const ControlCommandHandler& handler)
205{
206 if (validateParams(*parameters)) {
207 handler(prefix, interest, *parameters,
208 bind(&Dispatcher::sendControlResponse, this, _1, interest, false));
209 }
210 else {
211 sendControlResponse(ControlResponse(400, "failed in validating parameters"), interest);
212 }
213}
214
215void
216Dispatcher::sendControlResponse(const ControlResponse& resp, const Interest& interest,
217 bool isNack/*= false*/)
218{
219 MetaInfo info;
220 if (isNack) {
221 info.setType(tlv::ContentType_Nack);
222 }
223
224 sendData(interest.getName(), resp.wireEncode(), info);
225}
226
227void
228Dispatcher::addStatusDataset(const PartialName& relPrefix,
229 Authorization authorization,
230 StatusDatasetHandler handler)
231{
232 if (!m_topLevelPrefixes.empty()) {
233 BOOST_THROW_EXCEPTION(std::domain_error("one or more top-level prefix has been added"));
234 }
235
236 if (isOverlappedWithOthers(relPrefix)) {
237 BOOST_THROW_EXCEPTION(std::out_of_range("relPrefix overlapped"));
238 }
239
240 AuthorizationAcceptedCallback accepted =
241 bind(&Dispatcher::processAuthorizedStatusDatasetInterest, this,
242 _1, _2, _3, handler);
243 AuthorizationRejectedCallback rejected =
244 bind(&Dispatcher::afterAuthorizationRejected, this, _1, _2);
245 m_handlers[relPrefix] = bind(&Dispatcher::processStatusDatasetInterest, this,
246 _1, _2, authorization, accepted, rejected);
247}
248
249void
250Dispatcher::processStatusDatasetInterest(const Name& prefix,
251 const Interest& interest,
252 const Authorization& authorization,
253 const AuthorizationAcceptedCallback& accepted,
254 const AuthorizationRejectedCallback& rejected)
255{
256 const Name& interestName = interest.getName();
257 bool endsWithVersionOrSegment = interestName.size() >= 1 &&
258 (interestName[-1].isVersion() || interestName[-1].isSegment());
259 if (endsWithVersionOrSegment) {
260 return;
261 }
262
263 AcceptContinuation accept = bind(accepted, _1, prefix, interest, nullptr);
264 RejectContinuation reject = bind(rejected, _1, interest);
265 authorization(prefix, interest, nullptr, accept, reject);
266}
267
268void
269Dispatcher::processAuthorizedStatusDatasetInterest(const std::string& requester,
270 const Name& prefix,
271 const Interest& interest,
272 const StatusDatasetHandler& handler)
273{
274 StatusDatasetContext context(interest, bind(&Dispatcher::sendData, this, _1, _2, _3));
275 handler(prefix, interest, context);
276}
277
278PostNotification
279Dispatcher::addNotificationStream(const PartialName& relPrefix)
280{
281 if (!m_topLevelPrefixes.empty()) {
282 throw std::domain_error("one or more top-level prefix has been added");
283 }
284
285 if (isOverlappedWithOthers(relPrefix)) {
286 throw std::out_of_range("relPrefix overlaps with another relPrefix");
287 }
288
289 m_streams[relPrefix] = 0;
290 return bind(&Dispatcher::postNotification, this, _1, relPrefix);
291}
292
293void
294Dispatcher::postNotification(const Block& notification, const PartialName& relPrefix)
295{
296 if (m_topLevelPrefixes.empty() || m_topLevelPrefixes.size() > 1) {
297#ifdef NDN_CXX_MGMT_DISPATCHER_ENABLE_LOGGING
298 std::clog << "no top-level prefix or too many top-level prefixes" << std::endl;
299#endif // NDN_CXX_MGMT_DISPATCHER_ENABLE_LOGGING.
300 return;
301 }
302
303 Name streamName(m_topLevelPrefixes.begin()->second.topPrefix);
304 streamName.append(relPrefix);
305 streamName.appendSequenceNumber(m_streams[streamName]++);
306 sendData(streamName, notification, MetaInfo());
307}
308
309} // namespace mgmt
310} // namespace ndn