diff --git a/.gitignore b/.gitignore index e75e96c..e174cc3 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,8 @@ __pycache__/ *.py[cod] # Other -/VERSION \ No newline at end of file +/VERSION + + +RESOURCES/ +thesis/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..37b8d38 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# NDNSD +NDN Service Discovery diff --git a/docs/Directory Service.drawio b/docs/Directory Service.drawio new file mode 100644 index 0000000..2c72630 --- /dev/null +++ b/docs/Directory Service.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/seq_diagram_small.uml b/docs/seq_diagram_small.uml new file mode 100644 index 0000000..288a23d --- /dev/null +++ b/docs/seq_diagram_small.uml @@ -0,0 +1,29 @@ +@startuml +participant "Consumer \n (C)" as C +participant "ndnsd \n (d1)" as d1 +participant "ndnsd \n (d2)" as d2 +participant "Producer \n (P)" as P + +skinparam SequenceMessageAlign center +skinparam style strictuml + +P -> d2: publish service \n (type: printers, \n name: printer1 etc) +d2 -> P: status code \n (success, failed) +C -> d1: request service \n (e.g. printers) +d1 -> d1: Get service names \n (e.g. /printer1) via sync + +d1 -> d2: Interest (**I**): /printer1 + +note over d2 +send NACK if +service has expired +end note + +d2 -> d1: Application NACK +note over d2 +else send data +end note + +d2 -> d1: Data (**D**) : name = /printer1 \n content: "HP ledger jet" +d1 -> C: send response \n (service info/status) +@enduml diff --git a/docs/sequence_diagram_big.uml b/docs/sequence_diagram_big.uml new file mode 100644 index 0000000..d64ab08 --- /dev/null +++ b/docs/sequence_diagram_big.uml @@ -0,0 +1,36 @@ +@startuml +participant "Consumer \n (C)" as C +participant "NDNSD \n (d1)" as d1 +participant "NDNSD \n (d2)" as d2 +participant "Producer \n (P)" as P + +skinparam SequenceMessageAlign center +skinparam style strictuml + +P -> d2: publish service \n (type: printers, \n name: printer1 etc) +d2 -> P: status code +d2<--] : publish service "printer2" \n some other producer +C -> d1: request service \n (e.g. printers) +d1 -> d1: Get service names (/printer1, /printer2) via sync + +d1 -> d2 : iteratively fetch service info + loop each for service name + d1 -> d2: **I1:** /printer1, **I2:** /printer2 + end + +note over d2 +send NACK if +service has expired +end note + +d2 -> d1: NACK +note over d2 +else send data +end note + +d2 -> d1: Data (**D2**) : name = /printer1 \n content: "HP ledger jet" +d2 -> d1: Data (**D2**) : name = /printer2 \n content: "HP jet 400" + +d1 -> C: send D1 +d1 -> C: send D2 +@enduml diff --git a/docs/sequence_diagram_ndnsd_psync.uml b/docs/sequence_diagram_ndnsd_psync.uml new file mode 100644 index 0000000..b5263e5 --- /dev/null +++ b/docs/sequence_diagram_ndnsd_psync.uml @@ -0,0 +1,40 @@ +@startuml +participant "ndnsd \n (d1)" as d1 +participant "sync \n (s1)" as s1 +participant "sync \n (s2)" as s2 +participant "ndnsd \n (d2)" as d2 + + +skinparam SequenceMessageAlign center +skinparam style strictuml + +note over s1,s2 +Send periodic sync interest +end note +s1 -> s2: Sync interest: //IBF1 +s2 -> s1: Sync interest: //IBF1 + +note over d1 +Advertise service: +/printer1/1 +end note +d1 -> s1: p: /printer1/1 + +note over s1 +Publish service: /printer1/1 +insert into IBF1, get IBF2 +Answer pending interest +end note +s1 -> s2: Sync Data: //IBF1/IBF2 \n content: /printer/1 +s1 -> s2: Sync interest: //IBF2 +s1 -> d1: Callback, \n publish status + +note over s2 +Insert /printer/1 +to IBF1 and get IBF2 +end note +s2 -> d2: Update callback \n to ndnsd +note over s1,s2 +Send periodic sync interest +end note +@enduml diff --git a/examples/consumer.cpp b/examples/consumer.cpp index 6c418db..4b436c6 100644 --- a/examples/consumer.cpp +++ b/examples/consumer.cpp @@ -1,13 +1,140 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2014-2020, The University of Memphis + * + * This file is part of NDNSD. + * Author: Saurab Dulal (sdulal@memphis.edu) + * + * NDNSD is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * NDNSD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * NDNSD, e.g., in COPYING.md file. If not, see . + **/ + +#include "ndnsd/discovery/service-discovery.hpp" +#include #include +#include + +#include +#include +#include -class consumer +NDN_LOG_INIT(ndnsd.examples.ConsumerApp); + +static void +usage(const boost::program_options::options_description& options) { + std::cout << "Usage: ndnsd-consumer [options] e.g. printer \n" + << options; + exit(2); +} -}; +class Consumer +{ +public: + Consumer(const ndn::Name& serviceName, const std::map& pFlags) + : m_serviceDiscovery(serviceName, pFlags, std::bind(&Consumer::processCallback, this, _1)) + { + } + + void + execute () + { + // process and handle request + m_serviceDiscovery.consumerHandler(); + } + +private: + void + processCallback(const ndnsd::discovery::Reply& callback) + { + NDN_LOG_INFO("Service info received"); + auto status = (callback.status == ndnsd::discovery::ACTIVE)? "ACTIVE": "EXPIRED"; + std::cout << "Status: " << status << std::endl; + for (const auto& item : callback.serviceDetails) + { + std::cout << item.first << ": " << item.second << std::endl; + } + } + +private: + ndnsd::discovery::ServiceDiscovery m_serviceDiscovery; +}; -int main() +int +main(int argc, char* argv[]) { + std::string serviceName; + int contFlag = -1; + + namespace po = boost::program_options; + po::options_description visibleOptDesc("Options"); + + visibleOptDesc.add_options() + ("help,h", "print this message and exit") + ("serviceName,s", po::value(&serviceName)->required(), "Service name to fetch service info") + ("continuous,c", po::value(&contFlag), "continuous discovery, 1 for true 0 for false") + ; + + try + { + po::variables_map optVm; + po::store(po::parse_command_line(argc, argv, visibleOptDesc), optVm); + po::notify(optVm); + + if (optVm.count("continuous")) { + if (contFlag != ndnsd::discovery::OPTIONAL and contFlag != ndnsd::discovery::REQUIRED) + { + std::cout << "'c' must be either '0' or '1', default i.e. '0' will be used" << std::endl; + } + } + else + contFlag = 0; + + if (optVm.count("serviceName")) { + if (serviceName.empty()) + { + std::cerr << "ERROR: serviceName cannot be empty" << std::endl; + usage(visibleOptDesc); + } + } + + } + catch (const po::error& e) { + std::cerr << "ERROR: " << e.what() << std::endl; + usage(visibleOptDesc); + } + // TODO: protocol shouldn't be hard-coded. + std::map flags; + flags.insert(std::pair('p', ndnsd::SYNC_PROTOCOL_PSYNC)); //protocol choice + flags.insert(std::pair('t', ndnsd::discovery::CONSUMER)); //type producer: 1 + flags.insert(std::pair('c', contFlag)); + + try + { + std::cout << "Fetching service info for: " << serviceName << std::endl; + NDN_LOG_INFO("Fetching service info for: " << serviceName); + Consumer consumer(serviceName, flags); + consumer.execute(); + } + catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << std::endl; + NDN_LOG_ERROR("Cannot execute consumer, try again later: " << e.what()); + } + try { + Consumer consumer(argv[1], flags); + consumer.execute(); + } + catch (const std::exception& e) { + } } \ No newline at end of file diff --git a/examples/producer.cpp b/examples/producer.cpp index e69de29..911a7e4 100644 --- a/examples/producer.cpp +++ b/examples/producer.cpp @@ -0,0 +1,81 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2014-2020, The University of Memphis + * + * This file is part of NDNSD. + * Author: Saurab Dulal (sdulal@memphis.edu) + * + * NDNSD is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * NDNSD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * NDNSD, e.g., in COPYING.md file. If not, see . + **/ + +#include "ndnsd/discovery/service-discovery.hpp" +#include + +#include +#include + +NDN_LOG_INIT(ndnsd.examples.ProducerApp); + +inline bool +isFile(const std::string& fileName) +{ + return boost::filesystem::exists(fileName); +} + +class Producer +{ +public: + + Producer(const std::string& filename, const std::map& pFlags) + : m_serviceDiscovery(filename, pFlags, std::bind(&Producer::processCallback, this, _1)) + { + } + void + execute () + { + m_serviceDiscovery.producerHandler(); + } + +private: + void + processCallback(const ndnsd::discovery::Reply& callback) + { + NDN_LOG_INFO("Service publish callback received"); + auto status = (callback.status == ndnsd::discovery::ACTIVE)? "ACTIVE": "EXPIRED"; + std::cout << "\n Status: " << status << std::endl; + for (auto& item : callback.serviceDetails) + { + std::cout << item.first << ": " << item.second << std::endl; + } + } + +private: + ndnsd::discovery::ServiceDiscovery m_serviceDiscovery; +}; + +int +main(int argc, char* argv[]) +{ + std::map flags; + flags.insert(std::pair('p', ndnsd::SYNC_PROTOCOL_PSYNC)); //protocol choice + flags.insert(std::pair('t', ndnsd::discovery::PRODUCER)); //type producer: 1 + + try { + NDN_LOG_INFO("Starting producer application"); + Producer producer(argv[1], flags); + producer.execute(); + } + catch (const std::exception& e) { + std::cout << "Exception: " << e.what() << std::endl; + NDN_LOG_ERROR("Cannot execute producer, try again later: " << e.what()); + } +} \ No newline at end of file diff --git a/examples/wscript b/examples/wscript new file mode 100644 index 0000000..6d60187 --- /dev/null +++ b/examples/wscript @@ -0,0 +1,12 @@ +# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +top = '..' + +def build(bld): + # List all .cpp files (whole example in one .cpp) + for ex in bld.path.ant_glob('*.cpp'): + name = ex.change_ext('').path_from(bld.path.get_bld()) + bld.program(name='example-%s' % name, + target='ndnsd-%s' % name, + source=[ex], + use='ndnsd') diff --git a/logger.hpp b/logger.hpp new file mode 100644 index 0000000..7a3dbb0 --- /dev/null +++ b/logger.hpp @@ -0,0 +1,43 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2014-2019, The University of Memphis + * + * This file is part of NDNSD. + * See AUTHORS.md for complete list of NDNSD authors and contributors. + * + * NDNSD is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * NDNSD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * NDNSD, e.g., in COPYING.md file. If not, see . + **/ + +/*! \file logger.hpp + * \brief Define macros and auxiliary functions for logging. + * + * This file defines the macros that NDNSD uses for logging + * messages. An intrepid hacker could replace this system cleanly by + * providing a system that redefines all of the _LOG_* macros with an + * arbitrary system, as long as the underlying system accepts strings. + */ + +#ifndef NDNSD_LOGGER_HPP +#define NDNSD_LOGGER_HPP + +#include + +#define INIT_LOGGER(name) NDN_LOG_INIT(ndnsd.name) + +#define NDNSD_LOG_TRACE(x) NDN_LOG_TRACE(x) +#define NDNSD_LOG_DEBUG(x) NDN_LOG_DEBUG(x) +#define NDNSD_LOG_INFO(x) NDN_LOG_INFO(x) +#define NDNSD_LOG_WARN(x) NDN_LOG_WARN(x) +#define NDNSD_LOG_ERROR(x) NDN_LOG_ERROR(x) +#define NDNSD_LOG_FATAL(x) NDN_LOG_FATAL(x) + +#endif // NDNSD_LOGGER_HPP diff --git a/ndnsd.pc.in b/ndnsd.pc.in new file mode 100644 index 0000000..530774c --- /dev/null +++ b/ndnsd.pc.in @@ -0,0 +1,9 @@ +prefix=@PREFIX@ +libdir=@LIBDIR@ +includedir=@INCLUDEDIR@ + +Name: ndnsd +Description: NDN SD library +Version: @VERSION@ +Libs: -L${libdir} -lndnsd +Cflags: -I${includedir}abc diff --git a/src/communication/sync-adapter.cpp b/ndnsd/communication/sync-adapter.cpp similarity index 67% rename from src/communication/sync-adapter.cpp rename to ndnsd/communication/sync-adapter.cpp index f6873ea..ee09262 100644 --- a/src/communication/sync-adapter.cpp +++ b/ndnsd/communication/sync-adapter.cpp @@ -1,9 +1,9 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* - * Copyright (c) 2014-2019, The University of Memphis + * Copyright (c) 2014-2020, The University of Memphis * - * This file is part of NDNSD. - * See AUTHORS.md for complete list of NDNSD authors and contributors. + * This file is originally from NLSR and is modified here per the use. + * See NLSR's AUTHORS.md for complete list of NLSR authors and contributors. * * NDNSD is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Foundation, @@ -15,25 +15,31 @@ * * You should have received a copy of the GNU Lesser General Public License along with * NDNSD, e.g., in COPYING.md file. If not, see . + + @ most part of sync-adapter code is taken from NLSR/communication/ + **/ #include "sync-adapter.hpp" -// #include "logger.hpp" -// INIT_LOGGER(SyncProtocolAdapter); +#include + +#include + +NDN_LOG_INIT(ndnsd.SyncProtocolAdapter); namespace ndnsd { -const auto FIXED_SESSION = ndn::name::Component::fromNumber(0); +const auto CHRONOSYNC_FIXED_SESSION = ndn::name::Component::fromNumber(0); SyncProtocolAdapter::SyncProtocolAdapter(ndn::Face& face, - int32_t syncProtocol, + uint8_t syncProtocol, const ndn::Name& syncPrefix, const ndn::Name& userPrefix, ndn::time::milliseconds syncInterestLifetime, const SyncUpdateCallback& syncUpdateCallback) - : m_syncProtocol(syncProtocol) - , m_syncUpdateCallback(syncUpdateCallback) + : m_syncProtocol(syncProtocol) + , m_syncUpdateCallback(syncUpdateCallback) { if (m_syncProtocol == SYNC_PROTOCOL_CHRONOSYNC) { NDN_LOG_DEBUG("Using ChronoSync"); @@ -49,7 +55,7 @@ SyncProtocolAdapter::SyncProtocolAdapter(ndn::Face& face, syncInterestLifetime, chronosync::Logic::DEFAULT_SYNC_REPLY_FRESHNESS, chronosync::Logic::DEFAULT_RECOVERY_INTEREST_LIFETIME, - FIXED_SESSION); + CHRONOSYNC_FIXED_SESSION); } else { NDN_LOG_DEBUG("Using PSync"); @@ -66,7 +72,7 @@ void SyncProtocolAdapter::addUserNode(const ndn::Name& userPrefix) { if (m_syncProtocol == SYNC_PROTOCOL_CHRONOSYNC) { - m_chronoSyncLogic->addUserNode(userPrefix, chronosync::Logic::DEFAULT_NAME, FIXED_SESSION); + m_chronoSyncLogic->addUserNode(userPrefix, chronosync::Logic::DEFAULT_NAME, CHRONOSYNC_FIXED_SESSION); } else { m_psyncLogic->addUserNode(userPrefix); @@ -74,35 +80,48 @@ SyncProtocolAdapter::addUserNode(const ndn::Name& userPrefix) } void -SyncProtocolAdapter::publishUpdate(const ndn::Name& userPrefix, uint64_t seq) +SyncProtocolAdapter::publishUpdate(const ndn::Name& userPrefix) { + NDN_LOG_INFO("Publishing update for Sync Prefix " << userPrefix); if (m_syncProtocol == SYNC_PROTOCOL_CHRONOSYNC) { + auto seq = m_chronoSyncLogic->getSeqNo(userPrefix) + 1; + NDN_LOG_INFO("SeqNumber :" << seq); m_chronoSyncLogic->updateSeqNo(seq, userPrefix); } else { - m_psyncLogic->publishName(userPrefix, seq); + m_psyncLogic->publishName(userPrefix); } } void SyncProtocolAdapter::onChronoSyncUpdate(const std::vector& updates) { - NLSR_LOG_TRACE("Received ChronoSync update event"); + NDN_LOG_INFO("Received ChronoSync update event"); + std::vector dinfo; for (const auto& update : updates) { - // Remove FIXED_SESSION - m_syncUpdateCallback(update.session.getPrefix(-1), update.high); + // Remove CHRONOSYNC_FIXED_SESSION + SyncDataInfo di; + di.prefix = update.session.getPrefix(-1); + di.highSeq = update.high; + dinfo.insert(dinfo.begin(), di); } + m_syncUpdateCallback(dinfo); } void SyncProtocolAdapter::onPSyncUpdate(const std::vector& updates) { - NLSR_LOG_TRACE("Received PSync update event"); + NDN_LOG_INFO("Received PSync update event"); + std::vector dinfo; for (const auto& update : updates) { - m_syncUpdateCallback(update.prefix, update.highSeq); + SyncDataInfo di; + di.prefix = update.prefix; + di.highSeq = update.highSeq; + dinfo.insert(dinfo.begin(), di); } + m_syncUpdateCallback(dinfo); } } // namespace ndnsd \ No newline at end of file diff --git a/src/communication/sync-adapter.hpp b/ndnsd/communication/sync-adapter.hpp similarity index 80% rename from src/communication/sync-adapter.hpp rename to ndnsd/communication/sync-adapter.hpp index 9e42570..b59c763 100644 --- a/src/communication/sync-adapter.hpp +++ b/ndnsd/communication/sync-adapter.hpp @@ -1,9 +1,9 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* - * Copyright (c) 2014-2019, The University of Memphis + * Copyright (c) 2014-2020, The University of Memphis * - * This file is part of NDNSD. - * See AUTHORS.md for complete list of NDNSD authors and contributors. + * This file is originally from NLSR and is modified here per the use. + * See NLSR's AUTHORS.md for complete list of NLSR authors and contributors. * * NDNSD is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Foundation, @@ -15,27 +15,38 @@ * * You should have received a copy of the GNU Lesser General Public License along with * NDNSD, e.g., in COPYING.md file. If not, see . + + @ most part of sync-adapter code is taken from NLSR/communication/ + **/ #ifndef NDNSD_SYNC_ADAPTER_HPP #define NDNSD_SYNC_ADAPTER_HPP -#include "conf-parameter.hpp" - #include #include #include namespace ndnsd { -typedef std::function SyncUpdateCallback; +struct SyncDataInfo +{ + ndn::Name prefix; + uint64_t highSeq; +}; + +typedef std::function& updates)> SyncUpdateCallback; + +enum { + SYNC_PROTOCOL_CHRONOSYNC = 0, + SYNC_PROTOCOL_PSYNC = 1 +}; class SyncProtocolAdapter { public: SyncProtocolAdapter(ndn::Face& facePtr, - int32_t syncProtocol, + uint8_t syncProtocol, const ndn::Name& syncPrefix, const ndn::Name& userPrefix, ndn::time::milliseconds syncInterestLifetime, @@ -57,9 +68,9 @@ class SyncProtocolAdapter * \param seq the sequence of userPrefix */ void - publishUpdate(const ndn::Name& userPrefix, uint64_t seq); + publishUpdate(const ndn::Name& userPrefix); -PUBLIC_WITH_TESTS_ELSE_PRIVATE: +// PUBLIC_WITH_TESTS_ELSE_PRIVATE: /*! \brief Hook function to call whenever ChronoSync detects new data. * * This function packages the sync information into discrete updates @@ -83,7 +94,7 @@ class SyncProtocolAdapter onPSyncUpdate(const std::vector& updates); private: - int32_t m_syncProtocol; + uint8_t m_syncProtocol; SyncUpdateCallback m_syncUpdateCallback; std::shared_ptr m_chronoSyncLogic; std::shared_ptr m_psyncLogic; diff --git a/ndnsd/discovery/file-processor.cpp b/ndnsd/discovery/file-processor.cpp new file mode 100644 index 0000000..65a53a6 --- /dev/null +++ b/ndnsd/discovery/file-processor.cpp @@ -0,0 +1,95 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2014-2020, The University of Memphis + * + * This file is part of NDNSD. + * Author: Saurab Dulal (sdulal@memphis.edu) + * + * NDNSD is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * NDNSD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * NDNSD, e.g., in COPYING.md file. If not, see . + **/ + +#include "file-processor.hpp" + +#include + +#include + +NDN_LOG_INIT(ndnsd.FileProcessor); + +namespace ndnsd { +namespace discovery { + +ServiceInfoFileProcessor::ServiceInfoFileProcessor(const std::string filename) + : m_filename(filename) +{ + processFile(); +} + +// need to implement sanity check, 1. correct file is edited, required section is not modified +// and so on +void +ServiceInfoFileProcessor::processFile() +{ + try + { + NDN_LOG_INFO("Reading file: "<< m_filename); + boost::property_tree::ptree pt; + read_info(m_filename, pt); + for (auto& block: pt) + { + if (block.first == "required") + { + for (auto& requiredElement: block.second) + { + const auto& val = requiredElement.second.get_value(); + + if (requiredElement.first == "serviceName") + { + m_serviceName = val; + } + if (requiredElement.first == "appPrefix") + { + m_applicationPrefix = val; + } + if (requiredElement.first == "lifetime") + { + uint32_t lifetime = std::stoi(val); + m_serviceLifeTime = ndn::time::seconds(lifetime); + } + } + } + + if (block.first == "details") + { + m_serviceMetaInfo.clear(); + for (auto& details: block.second) + { + const auto& key = details.first; //get_value(); + const auto& val = details.second.get_value(); + + NDN_LOG_INFO("Reading file: "<< val); + m_serviceMetaInfo.insert(std::pair(key, val)); + } + } + } + NDN_LOG_INFO("Successfully updated the file content: "); + } + catch (std::exception const& e) + { + std::cerr << e.what() << std::endl; + NDN_LOG_INFO("Error reading file: " << m_filename); + throw e; + } +} + +} // namespace discovery +} // namespace ndnsd \ No newline at end of file diff --git a/ndnsd/discovery/file-processor.hpp b/ndnsd/discovery/file-processor.hpp new file mode 100644 index 0000000..2292bc5 --- /dev/null +++ b/ndnsd/discovery/file-processor.hpp @@ -0,0 +1,78 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2014-2020, The University of Memphis + * + * This file is part of NDNSD. + * Author: Saurab Dulal (sdulal@memphis.edu) + * + * NDNSD is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * NDNSD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * NDNSD, e.g., in COPYING.md file. If not, see . + **/ + +#ifndef NDNSD_FILE_PROCESSOR_HPP +#define NDNSD_FILE_PROCESSOR_HPP + +#include +#include + +#include +#include +#include + +namespace ndnsd { +namespace discovery { + +class ServiceInfoFileProcessor +{ +public: + + ServiceInfoFileProcessor() = default; + ServiceInfoFileProcessor(const std::string filename); + + ndn::Name& + getServiceName() + { + return m_serviceName; + } + + ndn::Name& + getAppPrefix() + { + return m_applicationPrefix; + } + + ndn::time::seconds + getServiceLifetime() + { + return m_serviceLifeTime; + } + + std::map& + getServiceMeta() + { + return m_serviceMetaInfo; + } + + void + processFile(); + +private: + const std::string m_filename; + ndn::Name m_serviceName; + ndn::Name m_applicationPrefix; + std::map m_serviceMetaInfo; + ndn::time::seconds m_serviceLifeTime; +}; + +} // namespace discovery +} // namespace ndnsd + +#endif // NDNSD_FILE_PROCESSOR_HPP \ No newline at end of file diff --git a/ndnsd/discovery/service-discovery.cpp b/ndnsd/discovery/service-discovery.cpp new file mode 100644 index 0000000..33f2ce0 --- /dev/null +++ b/ndnsd/discovery/service-discovery.cpp @@ -0,0 +1,401 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2014-2020, The University of Memphis + * + * This file is part of NDNSD. + * Author: Saurab Dulal (sdulal@memphis.edu) + * + * NDNSD is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * NDNSD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * NDNSD, e.g., in COPYING.md file. If not, see . + **/ + +#include "service-discovery.hpp" +#include +#include + +#include + +using namespace ndn::time_literals; + +NDN_LOG_INIT(ndnsd.ServiceDiscovery); + +namespace ndnsd { +namespace discovery { + +// consumer +ServiceDiscovery::ServiceDiscovery(const ndn::Name& serviceName, + const std::map& pFlags, + const DiscoveryCallback& discoveryCallback) + : m_serviceName(serviceName) + , m_appType(processFalgs(pFlags, 't', false)) + , m_counter(0) + , m_syncProtocol(processFalgs(pFlags, 'p', false)) + , m_syncAdapter(m_face, m_syncProtocol, makeSyncPrefix(m_serviceName), + "/defaultName", 1600_ms, + std::bind(&ServiceDiscovery::processSyncUpdate, this, _1)) + , m_discoveryCallback(discoveryCallback) +{ + // all the optional flag contDiscovery should be set here TODO: + m_continuousDiscovery = processFalgs(pFlags, 'c', true); +} + +// producer +ServiceDiscovery::ServiceDiscovery(const std::string& filename, + const std::map& pFlags, + const DiscoveryCallback& discoveryCallback) + : m_filename(filename) + , m_fileProcessor(m_filename) + , m_appType(processFalgs(pFlags, 't', false)) + , m_syncProtocol(processFalgs(pFlags, 'p', false)) + , m_syncAdapter(m_face, m_syncProtocol, makeSyncPrefix(m_fileProcessor.getServiceName()), + m_fileProcessor.getAppPrefix(), 1600_ms, + std::bind(&ServiceDiscovery::processSyncUpdate, this, _1)) + , m_discoveryCallback(discoveryCallback) +{ + setUpdateProducerState(); + setInterestFilter(m_producerState.applicationPrefix); + + // listen on reload prefix as well. + setInterestFilter(ndnsd::discovery::NDNSD_RELOAD_PREFIX); +} + +void +ServiceDiscovery::setUpdateProducerState(bool update) +{ + NDN_LOG_INFO("Setting/Updating producers state: "); + if (update) + { + m_fileProcessor.processFile(); + // should restrict updating service name and application prefix + if (m_producerState.serviceName != m_fileProcessor.getServiceName()) + NDN_LOG_ERROR("Service Name cannot be changed while application is running"); + if (m_producerState.applicationPrefix != m_fileProcessor.getAppPrefix()) + NDN_LOG_ERROR("Application Prefix cannot be changed while application is running"); + } + else + { + m_producerState.serviceName = m_fileProcessor.getServiceName(); + m_producerState.applicationPrefix = m_fileProcessor.getAppPrefix(); + } + // update + m_producerState.serviceLifetime = m_fileProcessor.getServiceLifetime(); + m_producerState.publishTimestamp = ndn::time::system_clock::now(); + m_producerState.serviceMetaInfo = m_fileProcessor.getServiceMeta(); +} + +ndn::Name +ServiceDiscovery::makeSyncPrefix(ndn::Name& service) +{ + ndn::Name sync("/discovery"); + sync.append(service); + return sync; +} + +uint8_t +ServiceDiscovery::processFalgs(const std::map& flags, + const char type, bool optional) +{ + if (flags.count(type) > 0) + { + return flags.find(type)->second; + } + else + { + if (!optional) + { + NDN_THROW(Error("Required flag type not found!")); + NDN_LOG_ERROR("Required flag type not found!"); + } + return 0; + } +} + +void +ServiceDiscovery::producerHandler() +{ + auto& prefix = m_producerState.applicationPrefix; + NDN_LOG_INFO("Advertising service under Name: " << prefix); + doUpdate(prefix); + run(); +} + +void +ServiceDiscovery::consumerHandler() +{ + NDN_LOG_INFO("Requesting service: " << m_serviceName); + run(); +} + +void +ServiceDiscovery::run() +{ + try + { + m_face.processEvents(); + } + catch (const std::exception& ex) { + std::cerr << ex.what() << std::endl; + NDN_LOG_ERROR("Face error: " << ex.what()); + } +} + +void +ServiceDiscovery::stop() +{ + m_face.shutdown(); + m_face.getIoService().stop(); +} + +void +ServiceDiscovery::setInterestFilter(const ndn::Name& name, const bool loopback) +{ + NDN_LOG_INFO("Setting interest filter on: " << name); + m_face.setInterestFilter(ndn::InterestFilter(name).allowLoopback(false), + std::bind(&ServiceDiscovery::processInterest, this, _1, _2), + std::bind(&ServiceDiscovery::onRegistrationSuccess, this, _1), + std::bind(&ServiceDiscovery::registrationFailed, this, _1)); +} + +void +ServiceDiscovery::processInterest(const ndn::Name& name, const ndn::Interest& interest) +{ + NDN_LOG_INFO("Interest received: " << interest.getName()); + auto interestName = interest.getName(); + + // check if the interest is for service detail or to update the service + if (interestName == NDNSD_RELOAD_PREFIX) + { + NDN_LOG_INFO("Receive request to reload service"); + // reload file. + m_fileProcessor.processFile(); + setUpdateProducerState(true); + + // if change is detected, call doUpdate to notify sync about the update + doUpdate(m_producerState.applicationPrefix); + // send back the response + static const std::string content("Update Successful"); + // Create Data packet + ndn::Data data(interest.getName()); + data.setFreshnessPeriod(1_ms); + data.setContent(reinterpret_cast(content.data()), content.size()); + + m_keyChain.sign(data); + m_face.put(data); + } + else + { + sendData(interest.getName()); + } +} + +std::string +ServiceDiscovery::makeDataContent() +{ + // reset the wire first + if(m_wire.hasWire()) + m_wire.reset(); + // |service-name||||||...and so on + std::string dataContent = "service-name"; + dataContent += "|"; + dataContent += m_producerState.applicationPrefix.toUri(); + + for (auto const& item : m_producerState.serviceMetaInfo) + { + dataContent += "|"; + dataContent += item.first; + dataContent += "|"; + dataContent += item.second; + } + return dataContent; +} + +void +ServiceDiscovery::sendData(const ndn::Name& name) +{ + NDN_LOG_INFO("Prepare to send data for name: " << name); + + auto timeDiff = ndn::time::system_clock::now() - m_producerState.publishTimestamp; + auto timeToExpire = ndn::time::duration_cast(timeDiff); + + int status = (timeToExpire > m_producerState.serviceLifetime) ? EXPIRED : ACTIVE; + + ndn::Data replyData(name); + replyData.setFreshnessPeriod(1_ms); + + auto dataContent = makeDataContent(); + replyData.setContent(wireEncode(dataContent, status)); + m_keyChain.sign(replyData); + m_face.put(replyData); + NDN_LOG_INFO("Data sent for name: " << name); +} + +void +ServiceDiscovery::expressInterest(const ndn::Name& name) +{ + NDN_LOG_INFO("Sending interest for name: " << name); + ndn::Interest interest(name); + interest.setCanBePrefix(false); + interest.setMustBeFresh(true); + interest.setInterestLifetime(160_ms); + + m_face.expressInterest(interest, + bind(&ServiceDiscovery::onData, this, _1, _2), + bind(&ServiceDiscovery::onTimeout, this, _1), + bind(&ServiceDiscovery::onTimeout, this, _1)); +} + +void +ServiceDiscovery::onData(const ndn::Interest& interest, const ndn::Data& data) +{ + data.getContent().parse(); + auto consumerReply = wireDecode(data.getContent().get(tlv::DiscoveryData)); + m_discoveryCallback(consumerReply); + m_counter--; + + // if continuous discovery is unset (i.e. OPTIONAL) consumer will be stopped + if (m_counter <= 0 && m_continuousDiscovery == OPTIONAL) + stop(); +} + +void +ServiceDiscovery::onTimeout(const ndn::Interest& interest) +{ + if (m_appType == CONSUMER) + { + m_counter--; + } + NDN_LOG_INFO("Interest: " << interest.getName() << "timeout"); +} + +void +ServiceDiscovery::registrationFailed(const ndn::Name& name) +{ + NDN_LOG_ERROR("ERROR: Failed to register prefix " << name << " in local hub's daemon"); +} + +void +ServiceDiscovery::onRegistrationSuccess(const ndn::Name& name) +{ + NDN_LOG_DEBUG("Successfully registered prefix: " << name); +} + +void +ServiceDiscovery::doUpdate(const ndn::Name& prefix) +{ + m_syncAdapter.publishUpdate(prefix); + NDN_LOG_INFO("Publish: " << prefix); +} + +void +ServiceDiscovery::processSyncUpdate(const std::vector& updates) +{ + m_counter = updates.size(); + if (m_appType == CONSUMER) + { + for (auto item: updates) + { + NDN_LOG_INFO("Fetching data for prefix:" << item.prefix); + expressInterest(item.prefix); + } + } + else + { + Reply consumerReply; + for (auto item: updates) + { + consumerReply.serviceDetails.insert(std::pair + ("prefix", item.prefix.toUri())); + consumerReply.status = ACTIVE; + m_discoveryCallback(consumerReply); + } + } +} + +template +size_t +ServiceDiscovery::wireEncode(ndn::EncodingImpl& encoder, + const std::string& info, int status) const +{ + size_t totalLength = 0; + totalLength += prependStringBlock(encoder, tlv::ServiceInfo, info); + totalLength += prependNonNegativeIntegerBlock(encoder, tlv::ServiceStatus, status); + totalLength += encoder.prependVarNumber(totalLength); + totalLength += encoder.prependVarNumber(tlv::DiscoveryData); + + return totalLength; +} + +const ndn::Block& +ServiceDiscovery::wireEncode(const std::string& info, int status) +{ + if (m_wire.hasWire()) + return m_wire; + + ndn::EncodingEstimator estimator; + size_t estimatedSize = wireEncode(estimator, info, status); + + ndn::EncodingBuffer buffer(estimatedSize, 0); + wireEncode(buffer, info, status); + m_wire = buffer.block(); + + return m_wire; +} + +std::map +ServiceDiscovery::processData(std::string reply) +{ + std::map keyVal; + std::vector items; + boost::split(items, reply, boost::is_any_of("|")); + for (size_t i = 0; i < items.size(); i += 2) + { + keyVal.insert(std::pair(items[i], items[i+1])); + } + return keyVal; +} + +Reply +ServiceDiscovery::wireDecode(const ndn::Block& wire) +{ + Reply consumerReply; + auto blockType = wire.type(); + + if (wire.type() != tlv::DiscoveryData) + { + NDN_LOG_ERROR("Expected DiscoveryData Block, but Block is of type: #" + << ndn::to_string(blockType)); + } + + wire.parse(); + m_wire = wire; + + ndn::Block::element_const_iterator it = m_wire.elements_begin(); + + if (it != m_wire.elements_end() && it->type() == tlv::ServiceStatus) { + consumerReply.status = ndn::readNonNegativeInteger(*it); + ++it; + } + else { + NDN_LOG_DEBUG("Service status is missing"); + } + + if (it != m_wire.elements_end() && it->type() == tlv::ServiceInfo) { + auto serviceMetaInfo = readString(*it); + consumerReply.serviceDetails = processData(readString(*it)); + } + else { + NDN_LOG_DEBUG("Service information not available"); + } + + return consumerReply; +} +} // namespace discovery +} // namespace ndnsd diff --git a/ndnsd/discovery/service-discovery.hpp b/ndnsd/discovery/service-discovery.hpp new file mode 100644 index 0000000..268d19c --- /dev/null +++ b/ndnsd/discovery/service-discovery.hpp @@ -0,0 +1,267 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2014-2020, The University of Memphis + * + * This file is part of NDNSD. + * Author: Saurab Dulal (sdulal@memphis.edu) + * + * NDNSD is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * NDNSD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * NDNSD, e.g., in COPYING.md file. If not, see . + **/ + +#ifndef NDNSD_SERVICE_DISCOVERY_HPP +#define NDNSD_SERVICE_DISCOVERY_HPP + +#include "ndnsd/communication/sync-adapter.hpp" + +#include "file-processor.hpp" + +#include +#include +#include +#include +#include + +using namespace ndn::time_literals; + +namespace ndnsd { +namespace discovery { +namespace tlv { + +enum { + DiscoveryData = 128, + ServiceInfo = 129, + ServiceStatus = 130 +}; + +} // namespace tlv + +enum { + PRODUCER = 0, + CONSUMER = 1, +}; + +enum { + OPTIONAL = 0, + REQUIRED = 1, +}; + +// service status +enum { + EXPIRED = 0, + ACTIVE = 1, +}; + +/** + each node will list on NDNSD_RELOAD_PREFIX, and will update their service once the + interest is received. +**/ +const char* NDNSD_RELOAD_PREFIX = "/ndnsd/reload"; + +struct Details +{ + /** + ndn::Name: serviceName: Service producer is willing to publish under. + syncPrefix will be constructed from the service type + e.g. serviceType printer, syncPrefix = //discovery/printer + map: serviceMetaInfo Detail information about the service, key-value map + ndn::Name applicationPrefix service provider application name + ndn::time timeStamp When the userPrefix was updated for the last time, default = now() + ndn::time prefixExpTime Lifetime of the service + **/ + + ndn::Name serviceName; + ndn::Name applicationPrefix; + ndn::time::seconds serviceLifetime; + ndn::time::system_clock::TimePoint publishTimestamp; + std::map serviceMetaInfo; +}; + +struct Reply +{ + std::map serviceDetails; + int status; +}; + +class Error : public std::runtime_error +{ +public: + using std::runtime_error::runtime_error; +}; + +typedef struct Details Details; +typedef struct Reply Reply; + +typedef std::function DiscoveryCallback; + +class ServiceDiscovery +{ + +public: + + /** + @brief constructor for consumer + + Creates a sync prefix from service type, fetches service name from sync, + iteratively fetches service info for each name, and sends it back to the consumer + + @param serviceName Service consumer is interested on. e.g. = printers + @param pFlags List of flags, i.e. sync protocol, application type etc + @param discoveryCallback + **/ + ServiceDiscovery(const ndn::Name& serviceName, + const std::map& pFlags, + const DiscoveryCallback& discoveryCallback); + + /** + @brief Constructor for producer + + Creates a sync prefix from service type, stores service info, sends publication + updates to sync, and listen on user-prefix to serve incoming requests + + @param filename Info file to load service details, sample below + + required + { + serviceName printer + appPrefix /printer1/service-info + lifetime 100 + } + details + { + description "Hp Ledger Jet" + make "2016" + } + ; all the keys in required field needs to have value + ; the details can have as many key-values are needed + + @param pFlags List of flags, i.e. sync protocol, application type etc + */ + + ServiceDiscovery(const std::string& filename, + const std::map& pFlags, + const DiscoveryCallback& discoveryCallback); + + void + run(); + + /* + @brief Cancel all pending operations, close connection to forwarder + and stop the ioService. + */ + void + stop(); + /* + @brief Handler exposed to producer application. Used to start the + discovery process + */ + void + producerHandler(); + + /* + @brief Handler exposed to producer application. Used to start the + discovery process + */ + void + consumerHandler(); + + uint32_t + getSyncProtocol() const + { + return m_syncProtocol; + } + + /* + @brief Process Type Flags send by consumer and producer application. + */ + uint8_t + processFalgs(const std::map& flags, + const char type, bool optional); + + ndn::Name + makeSyncPrefix(ndn::Name& service); + + std::string + makeDataContent(); + + std::map + processData(std::string reply); + +private: + void + doUpdate(const ndn::Name& prefix); + + void + setUpdateProducerState(bool update = false); + + void + processSyncUpdate(const std::vector& updates); + + void + processInterest(const ndn::Name& name, const ndn::Interest& interest); + + void + sendData(const ndn::Name& name); + + void + setInterestFilter(const ndn::Name& prefix, const bool loopback = false); + + void + registrationFailed(const ndn::Name& name); + + void + onRegistrationSuccess(const ndn::Name& name); + + void + onData(const ndn::Interest& interest, const ndn::Data& data); + + void + onTimeout(const ndn::Interest& interest); + + void + expressInterest(const ndn::Name& interest); + + template + size_t + wireEncode(ndn::EncodingImpl& block, const std::string& info, int status) const; + + const ndn::Block& + wireEncode(const std::string& info, int status); + + Reply + wireDecode(const ndn::Block& wire); + +private: + ndn::Face m_face; + ndn::KeyChain m_keyChain; + + const std::string m_filename; + ServiceInfoFileProcessor m_fileProcessor; + ndn::Name m_serviceName; + std::map m_Flags; + + Details m_producerState; + Reply m_consumerReply; + + uint8_t m_appType; + uint8_t m_counter; + + uint32_t m_syncProtocol; + uint32_t m_continuousDiscovery; + SyncProtocolAdapter m_syncAdapter; + static const ndn::Name DEFAULT_CONSUMER_ONLY_NAME; + mutable ndn::Block m_wire; + DiscoveryCallback m_discoveryCallback; + +}; +} //namespace discovery +} //namespace ndnsd +#endif // NDNSD_SERVICE_DISCOVERY_HPP \ No newline at end of file diff --git a/service_discovery.drawio b/service_discovery.drawio new file mode 100644 index 0000000..487bab3 --- /dev/null +++ b/service_discovery.drawio @@ -0,0 +1,1031 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/service_name.info b/service_name.info new file mode 100644 index 0000000..13b34b8 --- /dev/null +++ b/service_name.info @@ -0,0 +1 @@ +[{"serviceName": printer, "applicationPrefix": "/printer1", "Lifetime": "10_s"},{"Details": "Hp Ledger Jet"}] diff --git a/src/discovery/service-discovery.cpp b/src/discovery/service-discovery.cpp deleted file mode 100644 index 2f3e681..0000000 --- a/src/discovery/service-discovery.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2014-2019, The University of Memphis - * - * This file is part of NDNSD. - * See AUTHORS.md for complete list of NDNSD authors and contributors. - * - * NDNSD is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. - * - * NDNSD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * NDNSD, e.g., in COPYING.md file. If not, see . - **/ - -#include "service-discovery.hpp" - -#include - -NDN_LOG_INIT(examples.FullSyncApp); - -using namespace ndn::time_literals; - -class ServiceDiscovery -{ -public: - /** - * @brief Initialize producer and schedule updates - * - * Set IBF size as 80 expecting 80 updates to IBF in a sync cycle - * Set syncInterestLifetime and syncReplyFreshness to 1.6 seconds - * userPrefix is the default user prefix, no updates are published on it in this example - */ - ServiceDiscovery(const ndn::Name& syncPrefix, const std::string& userPrefix, - int numDataStreams, int maxNumPublish) - : m_scheduler(m_face.getIoService()) - , m_fullProducer(80, m_face, syncPrefix, userPrefix, - std::bind(&Producer::processSyncUpdate, this, _1), - 1600_ms, 1600_ms) - , m_numDataStreams(numDataStreams) - , m_maxNumPublish(maxNumPublish) - , m_rng(ndn::random::getRandomNumberEngine()) - , m_rangeUniformRandom(0, 60000) - { - // Add user prefixes and schedule updates for them in specified interval - for (int i = 0; i < m_numDataStreams; i++) { - ndn::Name prefix(userPrefix + "-" + ndn::to_string(i)); - m_fullProducer.addUserNode(prefix); - m_scheduler.schedule(ndn::time::milliseconds(m_rangeUniformRandom(m_rng)), - [this, prefix] { doUpdate(prefix); }); - } - } - - void - run() - { - m_face.processEvents(); - } -} - -void -ServiceDiscovery::run() -{ - m_face.processEvents(); -} - - -void -ServiceDiscovery::doUpdate(const ndn::Name& prefix) -{ - m_fullProducer.publishName(prefix); - - uint64_t seqNo = m_fullProducer.getSeqNo(prefix).value(); - NDN_LOG_INFO("Publish: " << prefix << "/" << seqNo); - - if (seqNo < m_maxNumPublish) { - m_scheduler.schedule(ndn::time::milliseconds(m_rangeUniformRandom(m_rng)), - [this, prefix] { doUpdate(prefix); }); - } -} - -void -ServiceDiscovery::processSyncUpdate(const std::vector& updates) -{ - for (const auto& update : updates) { - for (uint64_t i = update.lowSeq; i <= update.highSeq; i++) { - NDN_LOG_INFO("Update " << update.prefix << "/" << i); - } - } -} - -int -main(int argc, char* argv[]) -{ - if (argc != 5) { - std::cout << "usage: " << argv[0] << " " - << " " - << std::endl; - return 1; - } - - try { - Producer producer(argv[1], argv[2], std::stoi(argv[3]), std::stoi(argv[4])); - producer.run(); - } - catch (const std::exception& e) { - NDN_LOG_ERROR(e.what()); - } -} diff --git a/src/discovery/service-discovery.hpp b/src/discovery/service-discovery.hpp deleted file mode 100644 index 35fd8cc..0000000 --- a/src/discovery/service-discovery.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2014-2019, The University of Memphis - * - * This file is part of NDNSD. - * See AUTHORS.md for complete list of NDNSD authors and contributors. - * - * NDNSD is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. - * - * NDNSD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * NDNSD, e.g., in COPYING.md file. If not, see . - **/ - - -#ifndef NDNSD_SERVICE_DISCOVERY_HPP -#define NDNSD_SERVICE_DISCOVERY_HPP - -#include - -#include -#include -#include -#include - -#include - -using namespace ndn::time_literals; - -class ServiceDiscovery -{ - -public: - /** - * @brief Initialize producer and schedule updates - * - * Set IBF size as 80 expecting 80 updates to IBF in a sync cycle - * Set syncInterestLifetime and syncReplyFreshness to 1.6 seconds - * userPrefix is the default user prefix, no updates are published on it in this example - */ - ServiceDiscovery(const ndn::Name& syncPrefix, const std::string& userPrefix); - - void - run(); - -private: - void - doUpdate(); - - void - processSyncUpdate(); - - ndn::Face m_face; - ndn::Scheduler m_scheduler; - - psync::FullProducer m_fullProducer; - - int m_numDataStreams; - uint64_t m_maxNumPublish; - - ndn::random::RandomNumberEngine& m_rng; - std::uniform_int_distribution<> m_rangeUniformRandom; - -}; \ No newline at end of file diff --git a/test.info b/test.info new file mode 100644 index 0000000..dc09079 --- /dev/null +++ b/test.info @@ -0,0 +1,16 @@ +; all the item in the required section needs to be filled properly + +required +{ + serviceName printer + appPrefix /printer2/service-info + lifetime 20 +} + +; additional service details, user can put as many items as required + +details +{ + description "Hp Ledger Jet super xxx" + make "2016" +} diff --git a/tools/ndnsd-reload.cpp b/tools/ndnsd-reload.cpp new file mode 100644 index 0000000..455289e --- /dev/null +++ b/tools/ndnsd-reload.cpp @@ -0,0 +1,94 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2014-2020, The University of Memphis + * + * This file is part of NDNSD. + * Author: Saurab Dulal (sdulal@memphis.edu) + * + * NDNSD is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * NDNSD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * NDNSD, e.g., in COPYING.md file. If not, see . + **/ + +#define _GNU_SOURCE + +#include + +#include +#include +#include + +const char* NDNSD_RELOAD_PREFIX = "/ndnsd/reload"; + +class UpdateState +{ +public: + + UpdateState(int threshold) + : m_threshold(threshold) + { + expressInterest(); + } + + void + expressInterest() + { + ndn::Interest interest(NDNSD_RELOAD_PREFIX); + interest.setCanBePrefix(false); + interest.setMustBeFresh(true); + + std::cout << "Sending the reload interest: "<< interest << std::endl; + m_face.expressInterest(interest, + ndn::bind(&UpdateState::onData, this, _1, _2), + ndn::bind(&UpdateState::onTimeout, this, _1), + ndn::bind(&UpdateState::onTimeout, this, _1)); + } + + void + run() + { + m_face.processEvents(); + expressInterest(); + } + +private: + void + onData(const ndn::Interest& interest, const ndn::Data& data) + { + std::cout << "Update Successful" << data << std::endl; + // exit application + exit(0); + } + + void onTimeout(const ndn::Interest& interest) + { + if (m_threshold < 0) + { + // we have reached maximum retry + std::cout << "Update failed, please try again later" << std::endl; + exit(0); + } + expressInterest(); + m_threshold--; + } + +private: + int m_threshold; + ndn::Face m_face; +}; + +int main (int argv, char* argc[]) +{ + + int threshold = 2; + UpdateState us(threshold); + us.run(); + +} diff --git a/tools/wscript b/tools/wscript new file mode 100644 index 0000000..81cbcf9 --- /dev/null +++ b/tools/wscript @@ -0,0 +1,11 @@ +# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +top = '..' + +def build(bld): + # List all .cpp files (whole example in one .cpp) + for ex in bld.path.ant_glob('*.cpp'): + name = ex.change_ext('').path_from(bld.path.get_bld()) + bld.program(name='tools-%s' % name, + target='%s' % name, + source=[ex], + use='ndnsd') diff --git a/wscript b/wscript index b7a7930..da55e71 100644 --- a/wscript +++ b/wscript @@ -1,23 +1,4 @@ # -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -""" -Copyright (c) 2014-2019, The University of Memphis, - Regents of the University of California, - Arizona Board of Regents. - -This file is part of NLSR (Named-data Link State Routing). -See AUTHORS.md for complete list of NLSR authors and contributors. - -NLSR is free software: you can redistribute it and/or modify it under the terms -of the GNU General Public License as published by the Free Software Foundation, -either version 3 of the License, or (at your option) any later version. - -NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; -without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -NLSR, e.g., in COPYING.md file. If not, see . -""" from waflib import Context, Logs, Utils import os, subprocess @@ -26,8 +7,9 @@ VERSION = "0.0.1" APPNAME = "ndnsd" def options(opt): - opt.load(['compiler_cxx', 'gnu_dirs']) - opt.load(['default-compiler-flags', 'coverage', 'sanitizers', 'boost'], + opt.load(['compiler_c', 'compiler_cxx', 'gnu_dirs']) + opt.load(['default-compiler-flags', 'coverage', 'sanitizers', + 'boost'], tooldir=['.waf-tools']) optgrp = opt.add_option_group('ndnsd Options') @@ -35,8 +17,11 @@ def options(opt): help='Build examples') def configure(conf): - conf.load(['compiler_cxx', 'gnu_dirs', 'default-compiler-flags', 'boost']) + conf.load(['compiler_c', 'compiler_cxx', 'gnu_dirs', + 'default-compiler-flags', 'boost']) + conf.env.WITH_EXAMPLES = conf.options.with_examples + pkg_config_path = os.environ.get('PKG_CONFIG_PATH', '%s/pkgconfig' % conf.env.LIBDIR) conf.check_cfg(package='libndn-cxx', args=['--cflags', '--libs'], uselib_store='NDN_CXX', pkg_config_path=pkg_config_path) @@ -57,15 +42,18 @@ def configure(conf): conf.load('coverage') conf.load('sanitizers') - conf.define_cond('WITH_TESTS', conf.env.WITH_TESTS) + conf.env.prepend_value('STLIBPATH', ['.']) + # conf.define_cond('WITH_TESTS', conf.env.WITH_TESTS) # The config header will contain all defines that were added using conf.define() # or conf.define_cond(). Everything that was added directly to conf.env.DEFINES # will not appear in the config header, but will instead be passed directly to the # compiler on the command line. - conf.write_config_header('config.hpp') + conf.write_config_header('ndnsd/config.hpp') + def build(bld): - bld.shlib(target='ndnsd', + bld.shlib(features="c cshlib", + target='ndnsd', vnum=VERSION, cnum=VERSION, source=bld.path.ant_glob('ndnsd/**/*.cpp'), @@ -76,10 +64,12 @@ def build(bld): if bld.env.WITH_EXAMPLES: bld.recurse('examples') + bld.recurse('tools') + headers = bld.path.ant_glob('ndnsd/**/*.hpp') bld.install_files(bld.env.INCLUDEDIR, headers, relative_trick=True) - bld.install_files('${INCLUDEDIR}/ndnsd', + bld.install_files('${INCLUDEDIR}/ndnsd/', bld.path.find_resource('ndnsd/config.hpp')) bld(features='subst', @@ -139,4 +129,4 @@ def dist(ctx): version(ctx) def distcheck(ctx): - version(ctx) + version(ctx) \ No newline at end of file