blob: 492bcff292690f2237bfabadc728101c68177dad [file] [log] [blame]
Alison Craig2a4d5282015-04-10 12:00:02 -06001/** NDN-Atmos: Cataloging Service for distributed data originally developed
2 * for atmospheric science data
3 * Copyright (C) 2015 Colorado State University
4 *
5 * NDN-Atmos is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * NDN-Atmos is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with NDN-Atmos. If not, see <http://www.gnu.org/licenses/>.
17**/
18
19#ifndef ATMOS_PUBLISH_PUBLISH_ADAPTER_HPP
20#define ATMOS_PUBLISH_PUBLISH_ADAPTER_HPP
21
22#include "util/catalog-adapter.hpp"
23#include "util/mysql-util.hpp"
Chengyu Fanc7b87ad2015-07-09 16:44:37 -060024#include <mysql/mysql.h>
Alison Craig2a4d5282015-04-10 12:00:02 -060025
26#include <json/reader.h>
27#include <json/value.h>
28#include <json/writer.h>
29
30#include <ndn-cxx/face.hpp>
31#include <ndn-cxx/interest.hpp>
32#include <ndn-cxx/interest-filter.hpp>
33#include <ndn-cxx/name.hpp>
34#include <ndn-cxx/security/key-chain.hpp>
Chengyu Fanc7b87ad2015-07-09 16:44:37 -060035#include <ndn-cxx/security/validator-config.hpp>
Alison Craig2a4d5282015-04-10 12:00:02 -060036
37#include <memory>
38#include <string>
Chengyu Fanb25835b2015-04-28 17:09:35 -060039#include <vector>
40#include <unordered_map>
Alison Craig2a4d5282015-04-10 12:00:02 -060041
42namespace atmos {
43namespace publish {
Chengyu Fanc7b87ad2015-07-09 16:44:37 -060044
Alison Craig2a4d5282015-04-10 12:00:02 -060045/**
46 * PublishAdapter handles the Publish usecases for the catalog
47 */
48template <typename DatabaseHandler>
Chengyu Fanb25835b2015-04-28 17:09:35 -060049class PublishAdapter : public atmos::util::CatalogAdapter {
Alison Craig2a4d5282015-04-10 12:00:02 -060050public:
51 /**
52 * Constructor
53 *
Chengyu Fanb25835b2015-04-28 17:09:35 -060054 * @param face: Face that will be used for NDN communications
55 * @param keyChain: KeyChain that will be used for data signing
Alison Craig2a4d5282015-04-10 12:00:02 -060056 */
Chengyu Fanb25835b2015-04-28 17:09:35 -060057 PublishAdapter(const std::shared_ptr<ndn::Face>& face,
58 const std::shared_ptr<ndn::KeyChain>& keyChain);
Alison Craig2a4d5282015-04-10 12:00:02 -060059
Alison Craig2a4d5282015-04-10 12:00:02 -060060 virtual
61 ~PublishAdapter();
62
Chengyu Fanb25835b2015-04-28 17:09:35 -060063 /**
64 * Helper function that subscribe to a publish section for the config file
65 */
66 void
67 setConfigFile(util::ConfigFile& config,
68 const ndn::Name& prefix);
69
Alison Craig2a4d5282015-04-10 12:00:02 -060070protected:
71 /**
Chengyu Fanb25835b2015-04-28 17:09:35 -060072 * Helper function that configures piblishAdapter instance according to publish section
73 * in config file
74 */
75 void
76 onConfig(const util::ConfigSection& section,
77 bool isDryDun,
78 const std::string& fileName,
79 const ndn::Name& prefix);
80
81 /**
Alison Craig2a4d5282015-04-10 12:00:02 -060082 * Initial "please publish this" Interests
83 *
84 * @param filter: InterestFilter that caused this Interest to be routed
85 * @param interest: Interest that needs to be handled
86 */
87 virtual void
Chengyu Fanb25835b2015-04-28 17:09:35 -060088 onPublishInterest(const ndn::InterestFilter& filter, const ndn::Interest& interest);
Alison Craig2a4d5282015-04-10 12:00:02 -060089
90 /**
91 * Data containing the actual thing we need to publish
92 *
93 * @param interest: Interest that caused this Data to be routed
94 * @param data: Data that needs to be handled
95 */
96 virtual void
Chengyu Fanb25835b2015-04-28 17:09:35 -060097 onPublishedData(const ndn::Interest& interest, const ndn::Data& data);
Alison Craig2a4d5282015-04-10 12:00:02 -060098
Chengyu Fanb25835b2015-04-28 17:09:35 -060099 /**
100 * Helper function to set the DatabaseHandler
101 */
102 void
103 setDatabaseHandler(const util::ConnectionDetails& databaseId);
Alison Craig2a4d5282015-04-10 12:00:02 -0600104
Chengyu Fanb25835b2015-04-28 17:09:35 -0600105 /**
106 * Helper function that sets filters to make the adapter work
107 */
108 void
109 setFilters();
110
Chengyu Fanc7b87ad2015-07-09 16:44:37 -0600111 /**
112 * Function to validate publication changes against the trust model, which is, all file
113 * names must be under the publisher's prefix. This function should be called by a callback
114 * function invoked by validator
115 *
116 * @param data: received data from the publisher
117 */
118 bool
119 validatePublicationChanges(const std::shared_ptr<const ndn::Data>& data);
120
Chengyu Fanb25835b2015-04-28 17:09:35 -0600121protected:
122 typedef std::unordered_map<ndn::Name, const ndn::RegisteredPrefixId*> RegisteredPrefixList;
123 // Prefix for ChronoSync
124 ndn::Name m_syncPrefix;
125 // Handle to the Catalog's database
126 std::shared_ptr<DatabaseHandler> m_databaseHandler;
Chengyu Fanc7b87ad2015-07-09 16:44:37 -0600127 std::unique_ptr<ndn::ValidatorConfig> m_publishValidator;
Chengyu Fanb25835b2015-04-28 17:09:35 -0600128 RegisteredPrefixList m_registeredPrefixList;
Alison Craig2a4d5282015-04-10 12:00:02 -0600129};
130
Alison Craig2a4d5282015-04-10 12:00:02 -0600131
Chengyu Fanb25835b2015-04-28 17:09:35 -0600132template <typename DatabaseHandler>
133PublishAdapter<DatabaseHandler>::PublishAdapter(const std::shared_ptr<ndn::Face>& face,
134 const std::shared_ptr<ndn::KeyChain>& keyChain)
135 : util::CatalogAdapter(face, keyChain)
136{
137}
138
139template <typename DatabaseHandler>
140void
141PublishAdapter<DatabaseHandler>::setFilters()
142{
143 ndn::Name publishPrefix = ndn::Name(m_prefix).append("publish");
Chengyu Fanc7b87ad2015-07-09 16:44:37 -0600144 m_registeredPrefixList[publishPrefix] =
145 m_face->setInterestFilter(publishPrefix,
146 bind(&PublishAdapter<DatabaseHandler>::onPublishInterest,
147 this, _1, _2),
148 bind(&publish::PublishAdapter<DatabaseHandler>::onRegisterSuccess,
149 this, _1),
150 bind(&publish::PublishAdapter<DatabaseHandler>::onRegisterFailure,
151 this, _1, _2));
Alison Craig2a4d5282015-04-10 12:00:02 -0600152}
153
154template <typename DatabaseHandler>
155PublishAdapter<DatabaseHandler>::~PublishAdapter()
156{
Chengyu Fanb25835b2015-04-28 17:09:35 -0600157 for (const auto& itr : m_registeredPrefixList) {
158 if (static_cast<bool>(itr.second))
159 m_face->unsetInterestFilter(itr.second);
160 }
Alison Craig2a4d5282015-04-10 12:00:02 -0600161}
162
163template <typename DatabaseHandler>
164void
Chengyu Fanb25835b2015-04-28 17:09:35 -0600165PublishAdapter<DatabaseHandler>::setConfigFile(util::ConfigFile& config,
166 const ndn::Name& prefix)
167{
168 config.addSectionHandler("publishAdapter",
169 bind(&PublishAdapter<DatabaseHandler>::onConfig, this,
170 _1, _2, _3, prefix));
171}
172
173template <typename DatabaseHandler>
174void
175PublishAdapter<DatabaseHandler>::onConfig(const util::ConfigSection& section,
176 bool isDryRun,
177 const std::string& filename,
178 const ndn::Name& prefix)
179{
180 using namespace util;
181 if (isDryRun) {
182 return;
183 }
184
185 std::string signingId, dbServer, dbName, dbUser, dbPasswd;
186 std::string syncPrefix("ndn:/ndn-atmos/broadcast/chronosync");
187
188 for (auto item = section.begin();
189 item != section.end();
190 ++ item)
191 {
192 if (item->first == "signingId") {
193 signingId.assign(item->second.get_value<std::string>());
194 if (signingId.empty()) {
195 throw Error("Invalid value for \"signingId\""
196 " in \"publish\" section");
197 }
198 }
Chengyu Fanc7b87ad2015-07-09 16:44:37 -0600199 else if (item->first == "security") {
200 // when use, the validator must specify the callback func to handle the validated data
201 // it should be called when the Data packet that contains the published file names is received
202 m_publishValidator.reset(new ndn::ValidatorConfig(m_face.get()));
203 m_publishValidator->load(item->second, filename);
204 }
Chengyu Fanb25835b2015-04-28 17:09:35 -0600205 else if (item->first == "database") {
206 const util::ConfigSection& databaseSection = item->second;
207 for (auto subItem = databaseSection.begin();
208 subItem != databaseSection.end();
209 ++ subItem) {
210 if (subItem->first == "dbServer") {
211 dbServer.assign(subItem->second.get_value<std::string>());
212 if (dbServer.empty()){
213 throw Error("Invalid value for \"dbServer\""
214 " in \"publish\" section");
215 }
216 }
217 if (subItem->first == "dbName") {
218 dbName.assign(subItem->second.get_value<std::string>());
219 if (dbName.empty()){
220 throw Error("Invalid value for \"dbName\""
221 " in \"publish\" section");
222 }
223 }
224 if (subItem->first == "dbUser") {
225 dbUser.assign(subItem->second.get_value<std::string>());
226 if (dbUser.empty()){
227 throw Error("Invalid value for \"dbUser\""
228 " in \"publish\" section");
229 }
230 }
231 if (subItem->first == "dbPasswd") {
232 dbPasswd.assign(subItem->second.get_value<std::string>());
233 if (dbPasswd.empty()){
234 throw Error("Invalid value for \"dbPasswd\""
235 " in \"publish\" section");
236 }
237 }
238 }
239 }
240 else if (item->first == "sync") {
241 const util::ConfigSection& synSection = item->second;
242 for (auto subItem = synSection.begin();
243 subItem != synSection.end();
244 ++ subItem) {
245 if (subItem->first == "prefix") {
246 syncPrefix.clear();
247 syncPrefix.assign(subItem->second.get_value<std::string>());
248 if (syncPrefix.empty()){
249 throw Error("Invalid value for \"prefix\""
250 " in \"publish\\sync\" section");
251 }
252 }
253 // todo: parse the sync_security section
254 }
255 }
256 }
257
258 m_prefix = prefix;
259 m_signingId = ndn::Name(signingId);
260 m_syncPrefix.clear();
261 m_syncPrefix.append(syncPrefix);
262 util::ConnectionDetails mysqlId(dbServer, dbUser, dbPasswd, dbName);
263
264 setDatabaseHandler(mysqlId);
265 setFilters();
266}
267
268template <typename DatabaseHandler>
269void
270PublishAdapter<DatabaseHandler>::setDatabaseHandler(const util::ConnectionDetails& databaseId)
271{
272 //empty
273}
274
275template <>
276void
277PublishAdapter<MYSQL>::setDatabaseHandler(const util::ConnectionDetails& databaseId)
278{
279 std::shared_ptr<MYSQL> conn = atmos::util::MySQLConnectionSetup(databaseId);
280
281 m_databaseHandler = conn;
282}
283
284template <typename DatabaseHandler>
285void
286PublishAdapter<DatabaseHandler>::onPublishInterest(const ndn::InterestFilter& filter,
287 const ndn::Interest& interest)
Alison Craig2a4d5282015-04-10 12:00:02 -0600288{
289 // @todo: Request the data for publish
290}
291
292template <typename DatabaseHandler>
293void
Chengyu Fanb25835b2015-04-28 17:09:35 -0600294PublishAdapter<DatabaseHandler>::onPublishedData(const ndn::Interest& interest,
295 const ndn::Data& data)
Alison Craig2a4d5282015-04-10 12:00:02 -0600296{
Chengyu Fanc7b87ad2015-07-09 16:44:37 -0600297 // @todo handle data publication
298}
299
300template<typename DatabaseHandler>
301bool
302PublishAdapter<DatabaseHandler>::validatePublicationChanges(const std::shared_ptr<const ndn::Data>& data)
303{
304 // The data name must be "/<publisher-prefix>/<nonce>"
305 // the prefix is the data name removes the last component
306 ndn::Name publisherPrefix = data->getName().getPrefix(-1);
307
308 const std::string payload(reinterpret_cast<const char*>(data->getContent().value()),
309 data->getContent().value_size());
310 Json::Value parsedFromString;
311 Json::Reader reader;
312 if (!reader.parse(payload, parsedFromString)) {
313 // parse error, log events
314 std::cout << "Cannot parse the published data " << data->getName() << " into Json" << std::endl;
315 return false;
316 }
317
318 // validate added files...
319 for (size_t i = 0; i < parsedFromString["add"].size(); i++) {
320 if (!publisherPrefix.isPrefixOf(
321 ndn::Name(parsedFromString["add"][static_cast<int>(i)].asString())))
322 return false;
323 }
324
325 // validate removed files ...
326 for (size_t i = 0; i < parsedFromString["remove"].size(); i++) {
327 if (!publisherPrefix.isPrefixOf(
328 ndn::Name(parsedFromString["remove"][static_cast<int>(i)].asString())))
329 return false;
330 }
331 return true;
Alison Craig2a4d5282015-04-10 12:00:02 -0600332}
333
334} // namespace publish
335} // namespace atmos
336#endif //ATMOS_PUBLISH_PUBLISH_ADAPTER_HPP