blob: 9fb03dbe34eca1ca86eb8f1e97a5a8034f3ffd72 [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,
Chengyu Fan92440162015-07-09 14:43:31 -060068 const ndn::Name& prefix,
69 const std::vector<std::string>& nameFields);
Chengyu Fanb25835b2015-04-28 17:09:35 -060070
Alison Craig2a4d5282015-04-10 12:00:02 -060071protected:
72 /**
Chengyu Fanb25835b2015-04-28 17:09:35 -060073 * Helper function that configures piblishAdapter instance according to publish section
74 * in config file
75 */
76 void
77 onConfig(const util::ConfigSection& section,
78 bool isDryDun,
79 const std::string& fileName,
80 const ndn::Name& prefix);
81
82 /**
Alison Craig2a4d5282015-04-10 12:00:02 -060083 * Initial "please publish this" Interests
84 *
85 * @param filter: InterestFilter that caused this Interest to be routed
86 * @param interest: Interest that needs to be handled
87 */
88 virtual void
Chengyu Fanb25835b2015-04-28 17:09:35 -060089 onPublishInterest(const ndn::InterestFilter& filter, const ndn::Interest& interest);
Alison Craig2a4d5282015-04-10 12:00:02 -060090
91 /**
92 * Data containing the actual thing we need to publish
93 *
94 * @param interest: Interest that caused this Data to be routed
95 * @param data: Data that needs to be handled
96 */
97 virtual void
Chengyu Fanb25835b2015-04-28 17:09:35 -060098 onPublishedData(const ndn::Interest& interest, const ndn::Data& data);
Alison Craig2a4d5282015-04-10 12:00:02 -060099
Chengyu Fanb25835b2015-04-28 17:09:35 -0600100 /**
101 * Helper function to set the DatabaseHandler
102 */
103 void
104 setDatabaseHandler(const util::ConnectionDetails& databaseId);
Alison Craig2a4d5282015-04-10 12:00:02 -0600105
Chengyu Fanb25835b2015-04-28 17:09:35 -0600106 /**
107 * Helper function that sets filters to make the adapter work
108 */
109 void
110 setFilters();
111
Chengyu Fanc7b87ad2015-07-09 16:44:37 -0600112 /**
113 * Function to validate publication changes against the trust model, which is, all file
114 * names must be under the publisher's prefix. This function should be called by a callback
115 * function invoked by validator
116 *
117 * @param data: received data from the publisher
118 */
119 bool
120 validatePublicationChanges(const std::shared_ptr<const ndn::Data>& data);
121
Chengyu Fanb25835b2015-04-28 17:09:35 -0600122protected:
123 typedef std::unordered_map<ndn::Name, const ndn::RegisteredPrefixId*> RegisteredPrefixList;
124 // Prefix for ChronoSync
125 ndn::Name m_syncPrefix;
126 // Handle to the Catalog's database
127 std::shared_ptr<DatabaseHandler> m_databaseHandler;
Chengyu Fanc7b87ad2015-07-09 16:44:37 -0600128 std::unique_ptr<ndn::ValidatorConfig> m_publishValidator;
Chengyu Fanb25835b2015-04-28 17:09:35 -0600129 RegisteredPrefixList m_registeredPrefixList;
Alison Craig2a4d5282015-04-10 12:00:02 -0600130};
131
Alison Craig2a4d5282015-04-10 12:00:02 -0600132
Chengyu Fanb25835b2015-04-28 17:09:35 -0600133template <typename DatabaseHandler>
134PublishAdapter<DatabaseHandler>::PublishAdapter(const std::shared_ptr<ndn::Face>& face,
135 const std::shared_ptr<ndn::KeyChain>& keyChain)
136 : util::CatalogAdapter(face, keyChain)
137{
138}
139
140template <typename DatabaseHandler>
141void
142PublishAdapter<DatabaseHandler>::setFilters()
143{
144 ndn::Name publishPrefix = ndn::Name(m_prefix).append("publish");
Chengyu Fanc7b87ad2015-07-09 16:44:37 -0600145 m_registeredPrefixList[publishPrefix] =
146 m_face->setInterestFilter(publishPrefix,
147 bind(&PublishAdapter<DatabaseHandler>::onPublishInterest,
148 this, _1, _2),
149 bind(&publish::PublishAdapter<DatabaseHandler>::onRegisterSuccess,
150 this, _1),
151 bind(&publish::PublishAdapter<DatabaseHandler>::onRegisterFailure,
152 this, _1, _2));
Alison Craig2a4d5282015-04-10 12:00:02 -0600153}
154
155template <typename DatabaseHandler>
156PublishAdapter<DatabaseHandler>::~PublishAdapter()
157{
Chengyu Fanb25835b2015-04-28 17:09:35 -0600158 for (const auto& itr : m_registeredPrefixList) {
159 if (static_cast<bool>(itr.second))
160 m_face->unsetInterestFilter(itr.second);
161 }
Alison Craig2a4d5282015-04-10 12:00:02 -0600162}
163
164template <typename DatabaseHandler>
165void
Chengyu Fanb25835b2015-04-28 17:09:35 -0600166PublishAdapter<DatabaseHandler>::setConfigFile(util::ConfigFile& config,
Chengyu Fan92440162015-07-09 14:43:31 -0600167 const ndn::Name& prefix,
168 const std::vector<std::string>& nameFields)
Chengyu Fanb25835b2015-04-28 17:09:35 -0600169{
Chengyu Fan92440162015-07-09 14:43:31 -0600170 m_nameFields = nameFields;
Chengyu Fanb25835b2015-04-28 17:09:35 -0600171 config.addSectionHandler("publishAdapter",
172 bind(&PublishAdapter<DatabaseHandler>::onConfig, this,
173 _1, _2, _3, prefix));
174}
175
176template <typename DatabaseHandler>
177void
178PublishAdapter<DatabaseHandler>::onConfig(const util::ConfigSection& section,
179 bool isDryRun,
180 const std::string& filename,
181 const ndn::Name& prefix)
182{
183 using namespace util;
184 if (isDryRun) {
185 return;
186 }
187
188 std::string signingId, dbServer, dbName, dbUser, dbPasswd;
189 std::string syncPrefix("ndn:/ndn-atmos/broadcast/chronosync");
190
191 for (auto item = section.begin();
192 item != section.end();
193 ++ item)
194 {
195 if (item->first == "signingId") {
196 signingId.assign(item->second.get_value<std::string>());
197 if (signingId.empty()) {
198 throw Error("Invalid value for \"signingId\""
199 " in \"publish\" section");
200 }
201 }
Chengyu Fanc7b87ad2015-07-09 16:44:37 -0600202 else if (item->first == "security") {
203 // when use, the validator must specify the callback func to handle the validated data
204 // it should be called when the Data packet that contains the published file names is received
205 m_publishValidator.reset(new ndn::ValidatorConfig(m_face.get()));
206 m_publishValidator->load(item->second, filename);
207 }
Chengyu Fanb25835b2015-04-28 17:09:35 -0600208 else if (item->first == "database") {
209 const util::ConfigSection& databaseSection = item->second;
210 for (auto subItem = databaseSection.begin();
211 subItem != databaseSection.end();
212 ++ subItem) {
213 if (subItem->first == "dbServer") {
214 dbServer.assign(subItem->second.get_value<std::string>());
215 if (dbServer.empty()){
216 throw Error("Invalid value for \"dbServer\""
217 " in \"publish\" section");
218 }
219 }
220 if (subItem->first == "dbName") {
221 dbName.assign(subItem->second.get_value<std::string>());
222 if (dbName.empty()){
223 throw Error("Invalid value for \"dbName\""
224 " in \"publish\" section");
225 }
226 }
227 if (subItem->first == "dbUser") {
228 dbUser.assign(subItem->second.get_value<std::string>());
229 if (dbUser.empty()){
230 throw Error("Invalid value for \"dbUser\""
231 " in \"publish\" section");
232 }
233 }
234 if (subItem->first == "dbPasswd") {
235 dbPasswd.assign(subItem->second.get_value<std::string>());
236 if (dbPasswd.empty()){
237 throw Error("Invalid value for \"dbPasswd\""
238 " in \"publish\" section");
239 }
240 }
241 }
242 }
243 else if (item->first == "sync") {
244 const util::ConfigSection& synSection = item->second;
245 for (auto subItem = synSection.begin();
246 subItem != synSection.end();
247 ++ subItem) {
248 if (subItem->first == "prefix") {
249 syncPrefix.clear();
250 syncPrefix.assign(subItem->second.get_value<std::string>());
251 if (syncPrefix.empty()){
252 throw Error("Invalid value for \"prefix\""
253 " in \"publish\\sync\" section");
254 }
255 }
256 // todo: parse the sync_security section
257 }
258 }
259 }
260
261 m_prefix = prefix;
262 m_signingId = ndn::Name(signingId);
263 m_syncPrefix.clear();
264 m_syncPrefix.append(syncPrefix);
265 util::ConnectionDetails mysqlId(dbServer, dbUser, dbPasswd, dbName);
266
267 setDatabaseHandler(mysqlId);
268 setFilters();
269}
270
271template <typename DatabaseHandler>
272void
273PublishAdapter<DatabaseHandler>::setDatabaseHandler(const util::ConnectionDetails& databaseId)
274{
275 //empty
276}
277
278template <>
279void
280PublishAdapter<MYSQL>::setDatabaseHandler(const util::ConnectionDetails& databaseId)
281{
282 std::shared_ptr<MYSQL> conn = atmos::util::MySQLConnectionSetup(databaseId);
283
284 m_databaseHandler = conn;
285}
286
287template <typename DatabaseHandler>
288void
289PublishAdapter<DatabaseHandler>::onPublishInterest(const ndn::InterestFilter& filter,
290 const ndn::Interest& interest)
Alison Craig2a4d5282015-04-10 12:00:02 -0600291{
292 // @todo: Request the data for publish
293}
294
295template <typename DatabaseHandler>
296void
Chengyu Fanb25835b2015-04-28 17:09:35 -0600297PublishAdapter<DatabaseHandler>::onPublishedData(const ndn::Interest& interest,
298 const ndn::Data& data)
Alison Craig2a4d5282015-04-10 12:00:02 -0600299{
Chengyu Fanc7b87ad2015-07-09 16:44:37 -0600300 // @todo handle data publication
301}
302
303template<typename DatabaseHandler>
304bool
305PublishAdapter<DatabaseHandler>::validatePublicationChanges(const std::shared_ptr<const ndn::Data>& data)
306{
307 // The data name must be "/<publisher-prefix>/<nonce>"
308 // the prefix is the data name removes the last component
309 ndn::Name publisherPrefix = data->getName().getPrefix(-1);
310
311 const std::string payload(reinterpret_cast<const char*>(data->getContent().value()),
312 data->getContent().value_size());
313 Json::Value parsedFromString;
314 Json::Reader reader;
315 if (!reader.parse(payload, parsedFromString)) {
316 // parse error, log events
317 std::cout << "Cannot parse the published data " << data->getName() << " into Json" << std::endl;
318 return false;
319 }
320
321 // validate added files...
322 for (size_t i = 0; i < parsedFromString["add"].size(); i++) {
323 if (!publisherPrefix.isPrefixOf(
324 ndn::Name(parsedFromString["add"][static_cast<int>(i)].asString())))
325 return false;
326 }
327
328 // validate removed files ...
329 for (size_t i = 0; i < parsedFromString["remove"].size(); i++) {
330 if (!publisherPrefix.isPrefixOf(
331 ndn::Name(parsedFromString["remove"][static_cast<int>(i)].asString())))
332 return false;
333 }
334 return true;
Alison Craig2a4d5282015-04-10 12:00:02 -0600335}
336
337} // namespace publish
338} // namespace atmos
339#endif //ATMOS_PUBLISH_PUBLISH_ADAPTER_HPP