add logger
Change-Id: If41d6d94086ec9fffb954a52e1529ccfad7f42fe
diff --git a/core/logger.cpp b/core/logger.cpp
new file mode 100644
index 0000000..6a1e67c
--- /dev/null
+++ b/core/logger.cpp
@@ -0,0 +1,306 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#include "logger.hpp"
+#include "tlv.hpp"
+#include "conf/config-file.hpp"
+
+namespace nsl {
+
+const int Logger::N_DATA_FETCHING_RETRIAL = 2;
+
+Logger::Logger(ndn::Face& face, const std::string& configFile)
+ : m_face(face)
+ , m_merkleTree(m_db)
+ , m_validator(m_face)
+{
+ conf::ConfigFile conf(configFile);
+ conf.parse();
+
+ m_loggerName = conf.getLoggerName();
+
+ m_treePrefix = m_loggerName;
+ m_treePrefix.append("tree");
+ m_leafPrefix = m_loggerName;
+ m_leafPrefix.append("leaf");
+ m_logPrefix = m_loggerName;
+ m_logPrefix.append("log");
+
+ m_merkleTree.setLoggerName(m_treePrefix);
+ m_merkleTree.loadPendingSubTrees();
+
+ m_db.open(conf.getDbDir());
+
+ // initialize security environment: keychain
+ initializeKeys();
+
+ // load policy checker
+ m_policyChecker.loadPolicy(conf.getPolicy());
+
+ // load validator rules
+ m_validator.load(conf.getValidatorRule(), conf.getConfFileName());
+
+ // register subtree prefix
+ m_face.setInterestFilter(m_treePrefix,
+ bind(&Logger::onSubTreeInterest, this, _1, _2),
+ [] (const Name&) {},
+ [] (const Name&, const std::string&) {});
+
+ // register leaf prefix
+ m_face.setInterestFilter(m_leafPrefix,
+ bind(&Logger::onLeafInterest, this, _1, _2),
+ [] (const Name&) {},
+ [] (const Name&, const std::string&) {});
+
+ // register log prefix
+ m_face.setInterestFilter(m_logPrefix,
+ bind(&Logger::onLogRequestInterest, this, _1, _2),
+ [] (const Name&) {},
+ [] (const Name&, const std::string&) {});
+}
+
+NonNegativeInteger
+Logger::addSelfSignedCert(ndn::IdentityCertificate& cert, const Timestamp& timestamp)
+{
+ if (!ndn::Validator::verifySignature(cert, cert.getPublicKeyInfo()))
+ throw Error("Not self-signed cert");
+
+ NonNegativeInteger dataSeqNo = m_merkleTree.getNextLeafSeqNo();
+ Leaf leaf(cert.getFullName(), timestamp, dataSeqNo, dataSeqNo, m_leafPrefix);
+
+ if (m_merkleTree.addLeaf(dataSeqNo, leaf.getHash())) {
+ bool result = m_db.insertLeafData(leaf, cert);
+ BOOST_ASSERT(result);
+ m_db.getLeaf(dataSeqNo);
+ }
+ else
+ throw Error("Cannot add cert");
+
+ return dataSeqNo;
+}
+
+void
+Logger::initializeKeys()
+{
+ Name certName = m_keyChain.createIdentity(m_loggerName);
+
+ Name dskKeyName = m_keyChain.generateEcdsaKeyPair(m_loggerName);
+ std::vector<ndn::CertificateSubjectDescription> subjectDescription;
+ auto dskCert =
+ m_keyChain.prepareUnsignedIdentityCertificate(dskKeyName, m_loggerName,
+ time::system_clock::now(),
+ time::system_clock::now() + time::days(1),
+ subjectDescription);
+ m_keyChain.sign(*dskCert, certName);
+ m_keyChain.addCertificate(*dskCert);
+ m_dskCert = dskCert;
+}
+
+void
+Logger::onSubTreeInterest(const ndn::InterestFilter& interestFilter, const Interest& interest)
+{
+ Name interestName = interest.getName();
+
+ size_t levelOffset = m_treePrefix.size();
+ size_t seqNoOffset = m_treePrefix.size() + 1;
+
+ if (interestName.size() < seqNoOffset + 1)
+ return; // interest is too short to answer
+
+ NonNegativeInteger level;
+ NonNegativeInteger seqNo;
+
+ try {
+ seqNo = interestName.get(seqNoOffset).toNumber();
+ level = interestName.get(levelOffset).toNumber();
+ }
+ catch (tlv::Error&) {
+ return;
+ }
+
+ Node::Index peakIndex = SubTreeBinary::toSubTreePeakIndex(Node::Index(seqNo, level));
+ shared_ptr<Data> data;
+
+ data = m_merkleTree.getPendingSubTreeData(peakIndex.level);
+
+ if (data != nullptr && interestName.isPrefixOf(data->getName())) {
+ m_face.put(*data);
+ return;
+ }
+
+ data = m_db.getSubTreeData(peakIndex.level, peakIndex.seqNo);
+
+ if (data != nullptr && interestName.isPrefixOf(data->getName())) {
+ m_face.put(*data);
+ return;
+ }
+}
+
+void
+Logger::onLeafInterest(const ndn::InterestFilter& interestFilter, const Interest& interest)
+{
+ Name interestName = interest.getName();
+
+ size_t seqNoOffset = m_leafPrefix.size();
+ size_t hashOffset = m_leafPrefix.size() + 1;
+
+ if (interestName.size() < seqNoOffset + 1)
+ return; // interest is too short to answer
+
+ NonNegativeInteger seqNo;
+
+ try {
+ seqNo = interestName.get(seqNoOffset).toNumber();
+ }
+ catch (tlv::Error&) {
+ return;
+ }
+ auto result = m_db.getLeaf(seqNo);
+
+ if (result.first != nullptr) {
+ if (interestName.size() >= hashOffset + 1) {
+ ndn::ConstBufferPtr leafHash;
+ try {
+ leafHash = make_shared<ndn::Buffer>(interestName.get(hashOffset).value(),
+ interestName.get(hashOffset).value_size());
+ ndn::ConstBufferPtr hash = result.first->getHash();
+ if (*hash != *leafHash)
+ return;
+ }
+ catch (tlv::Error&) {
+ return;
+ }
+ }
+ result.first->setLoggerName(m_leafPrefix);
+ m_face.put(*result.first->encode());
+ }
+}
+
+void
+Logger::onLogRequestInterest(const ndn::InterestFilter& interestFilter, const Interest& interest)
+{
+ m_validator.validate(interest,
+ bind(&Logger::requestValidatedCallback, this, _1),
+ [] (const shared_ptr<const Interest>&, const std::string&) {});
+}
+
+void
+Logger::requestValidatedCallback(const shared_ptr<const Interest>& interest)
+{
+ BOOST_ASSERT(interest->getName().size() == (m_logPrefix.size() + 6));
+
+ Name request = interest->getName().getPrefix(-4); // TODO: remove sig-related components
+
+ size_t dataOffset = m_logPrefix.size();
+ size_t signerOffset = m_logPrefix.size() + 1;
+
+ if (request.size() < signerOffset + 1)
+ return; // request is too short to answer
+
+ Name dataName;
+ NonNegativeInteger signerSeqNo;
+ try {
+ dataName.wireDecode(request.get(dataOffset).blockFromValue());
+ signerSeqNo = request.get(signerOffset).toNumber();
+ }
+ catch (tlv::Error&) {
+ return;
+ }
+
+ auto result = m_db.getLeaf(signerSeqNo);
+ if (result.first == nullptr || result.second == nullptr)
+ return;
+
+ Interest dataInterest(dataName);
+ m_face.expressInterest(dataInterest,
+ bind(&Logger::dataReceivedCallback, this, _1, _2,
+ signerSeqNo, *interest),
+ bind(&Logger::dataTimeoutCallback, this, _1,
+ N_DATA_FETCHING_RETRIAL, signerSeqNo, *interest));
+}
+
+void
+Logger::dataReceivedCallback(const Interest& interest, Data& data,
+ const NonNegativeInteger& signerSeqNo,
+ const Interest& reqInterest)
+{
+ auto result = m_db.getLeaf(signerSeqNo);
+ BOOST_ASSERT(result.first != nullptr);
+ BOOST_ASSERT(result.second != nullptr);
+
+ Timestamp dataTimestamp = time::toUnixTimestamp(time::system_clock::now()).count() / 1000;
+
+ try {
+ ndn::IdentityCertificate cert(*result.second);
+
+ if (m_policyChecker.check(dataTimestamp, data, result.first->getTimestamp(), cert)) {
+ NonNegativeInteger dataSeqNo = m_merkleTree.getNextLeafSeqNo();
+ Leaf leaf(data.getFullName(), dataTimestamp, dataSeqNo, signerSeqNo, m_leafPrefix);
+
+ if (m_merkleTree.addLeaf(dataSeqNo, leaf.getHash())) {
+ if (data.getContentType() == ndn::tlv::ContentType_Key)
+ m_db.insertLeafData(leaf, data);
+ else
+ m_db.insertLeafData(leaf);
+
+ makeLogResponse(reqInterest, LoggerResponse(dataSeqNo));
+ }
+ else
+ makeLogResponse(reqInterest,
+ LoggerResponse(tlv::LogResponse_Error_Tree, "cannot add leaf"));
+ }
+ else
+ makeLogResponse(reqInterest,
+ LoggerResponse(tlv::LogResponse_Error_Policy, "cannot pass policy checking"));
+ }
+ catch (tlv::Error&) {
+ makeLogResponse(reqInterest,
+ LoggerResponse(tlv::LogResponse_Error_Signer, "signer is wrong"));
+ }
+}
+
+void
+Logger::dataTimeoutCallback(const Interest& interest, int nRetrials,
+ const NonNegativeInteger& signerSeqNo,
+ const Interest& reqInterest)
+{
+ if (nRetrials > 0) {
+ m_face.expressInterest(interest,
+ bind(&Logger::dataReceivedCallback, this, _1, _2,
+ signerSeqNo, reqInterest),
+ bind(&Logger::dataTimeoutCallback, this, _1,
+ nRetrials - 1, signerSeqNo, reqInterest));
+ }
+}
+
+void
+Logger::makeLogResponse(const Interest& reqInterest, const LoggerResponse& response)
+{
+ auto data = make_shared<Data>(reqInterest.getName());
+ data->setContent(response.wireEncode());
+
+ BOOST_ASSERT(m_dskCert != nullptr);
+ m_keyChain.sign(*data, m_dskCert->getName());
+ m_face.put(*data);
+}
+
+
+} // namespace nsl
diff --git a/core/logger.hpp b/core/logger.hpp
new file mode 100644
index 0000000..a53b0aa
--- /dev/null
+++ b/core/logger.hpp
@@ -0,0 +1,140 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#ifndef NSL_CORE_LOGGER_HPP
+#define NSL_CORE_LOGGER_HPP
+
+#include "common.hpp"
+#include "logger-response.hpp"
+#include "db.hpp"
+#include "policy-checker.hpp"
+#include "merkle-tree.hpp"
+#include "util/non-negative-integer.hpp"
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/security/validator-config.hpp>
+
+namespace nsl {
+
+class Logger
+{
+public:
+ class Error : public std::runtime_error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : std::runtime_error(what)
+ {
+ }
+ };
+
+public:
+ Logger(ndn::Face& face, const std::string& configFile);
+
+ NonNegativeInteger
+ addSelfSignedCert(ndn::IdentityCertificate& cert, const Timestamp& timestamp);
+
+NSL_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+ void
+ initializeKeys();
+
+ void
+ loadConfiguration(const std::string& filename);
+
+ void
+ onSubTreeInterest(const ndn::InterestFilter& interestFilter, const Interest& interest);
+
+ void
+ onLeafInterest(const ndn::InterestFilter& interestFilter, const Interest& interest);
+
+ void
+ onLogRequestInterest(const ndn::InterestFilter& interestFilter, const Interest& interest);
+
+ void
+ requestValidatedCallback(const shared_ptr<const Interest>& interest);
+
+ void
+ dataReceivedCallback(const Interest& interest, Data& data,
+ const NonNegativeInteger& signerSeqNo,
+ const Interest& reqInterest);
+
+ void
+ dataTimeoutCallback(const Interest& interest, int nRetrials,
+ const NonNegativeInteger& signerSeqNo,
+ const Interest& reqInterest);
+
+ void
+ makeLogResponse(const Interest& reqInterest, const LoggerResponse& response);
+
+ const Name&
+ getLoggerName() const
+ {
+ return m_loggerName;
+ }
+
+ const Name&
+ getTreePrefix() const
+ {
+ return m_treePrefix;
+ }
+
+ const Name&
+ getLeafPrefix() const
+ {
+ return m_leafPrefix;
+ }
+
+ const Name&
+ getLogPrefix() const
+ {
+ return m_logPrefix;
+ }
+
+ Db&
+ getDb()
+ {
+ return m_db;
+ }
+
+private:
+ static const int N_DATA_FETCHING_RETRIAL;
+
+private:
+ ndn::Face& m_face;
+ Name m_loggerName;
+ Name m_treePrefix;
+ Name m_leafPrefix;
+ Name m_logPrefix;
+
+ Db m_db;
+ MerkleTree m_merkleTree;
+
+ ndn::KeyChain m_keyChain;
+ shared_ptr<ndn::IdentityCertificate> m_dskCert;
+
+ ndn::ValidatorConfig m_validator;
+ PolicyChecker m_policyChecker;
+};
+
+} // namespace nsl
+
+#endif // NSL_CORE_LOGGER_HPP
diff --git a/daemon/main.cpp b/daemon/main.cpp
index d172f7d..d0b6bd0 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -19,8 +19,71 @@
* \author Yingdi Yu <yingdi@cs.ucla.edu>
*/
+#include "../core/logger.hpp"
+
+#include <boost/program_options/options_description.hpp>
+#include <boost/program_options/variables_map.hpp>
+#include <boost/program_options/parsers.hpp>
+#include <boost/filesystem.hpp>
+
+
int
main(int argc, char** argv)
{
+ namespace po = boost::program_options;
+ namespace fs = boost::filesystem;
+
+ std::string configFile;
+
+ po::options_description description("General Usage\n"
+ " nsl [-h] [-c config]\n"
+ "General options");
+ description.add_options()
+ ("help,h", "produce help message")
+ ("config,c", po::value<std::string>(&configFile))
+ ;
+
+ po::variables_map vm;
+ try {
+ po::store(po::parse_command_line(argc, argv, description), vm);
+ po::notify(vm);
+ }
+ catch (const std::exception& e) {
+ std::cerr << "ERROR: " << e.what() << std::endl;
+ std::cerr << description << std::endl;
+ return 1;
+ }
+
+ if (vm.count("help") != 0) {
+ std::cerr << description << std::endl;
+ return 0;
+ }
+
+ if (vm.count("config") == 0) {
+
+ if (!getenv("HOME")) {
+ configFile = "/usr/local/etc/ndn/nsl.conf";
+ }
+ else {
+ configFile = getenv("HOME");
+ configFile += "/.ndn/nsl.conf";
+ }
+
+ if (!fs::exists(fs::path(configFile))) {
+ std::cerr << "ERROR: config file is not available: " << configFile << std::endl;
+ return 1;
+ }
+ }
+
+ try {
+ ndn::Face face;
+ nsl::Logger(face, configFile);
+ face.processEvents();
+ }
+ catch (std::runtime_error& e) {
+ std::cerr << e.what() << std::endl;
+ return 1;
+ }
+
return 0;
}
diff --git a/tests/core/logger.t.cpp b/tests/core/logger.t.cpp
new file mode 100644
index 0000000..521be9b
--- /dev/null
+++ b/tests/core/logger.t.cpp
@@ -0,0 +1,335 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014, Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#include "logger.hpp"
+#include "identity-fixture.hpp"
+#include "db-fixture.hpp"
+#include <ndn-cxx/util/dummy-client-face.hpp>
+#include <ndn-cxx/util/io.hpp>
+
+#include "boost-test.hpp"
+
+namespace nsl {
+namespace tests {
+
+class LoggerFixture : public IdentityFixture
+ , public DbFixture
+{
+public:
+ LoggerFixture()
+ : face1(ndn::util::makeDummyClientFace(io, {true, true}))
+ , face2(ndn::util::makeDummyClientFace(io, {true, true}))
+ , readInterestOffset1(0)
+ , readDataOffset1(0)
+ , readInterestOffset2(0)
+ , readDataOffset2(0)
+ {
+ }
+
+ ~LoggerFixture()
+ {
+ }
+
+ bool
+ passPacket()
+ {
+ bool hasPassed = false;
+
+ checkFace(face1->sentInterests, readInterestOffset1, *face2, hasPassed);
+ checkFace(face1->sentDatas, readDataOffset1, *face2, hasPassed);
+ checkFace(face2->sentInterests, readInterestOffset2, *face1, hasPassed);
+ checkFace(face2->sentDatas, readDataOffset2, *face1, hasPassed);
+
+ return hasPassed;
+ }
+
+ template<typename Packet>
+ void
+ checkFace(std::vector<Packet>& receivedPackets,
+ size_t& readPacketOffset,
+ ndn::util::DummyClientFace& receiver,
+ bool& hasPassed)
+ {
+ while (receivedPackets.size() > readPacketOffset) {
+ receiver.receive(receivedPackets[readPacketOffset]);
+ readPacketOffset++;
+ hasPassed = true;
+ }
+ }
+
+ void
+ clear()
+ {
+ face1->sentDatas.clear();
+ face1->sentInterests.clear();
+ face2->sentDatas.clear();
+ face2->sentInterests.clear();
+
+ readInterestOffset1 = 0;
+ readDataOffset1 = 0;
+ readInterestOffset2 = 0;
+ readDataOffset2 = 0;
+ }
+
+public:
+ shared_ptr<ndn::util::DummyClientFace> face1;
+ shared_ptr<ndn::util::DummyClientFace> face2;
+
+ size_t readInterestOffset1;
+ size_t readDataOffset1;
+ size_t readInterestOffset2;
+ size_t readDataOffset2;
+};
+
+BOOST_FIXTURE_TEST_SUITE(TestLogger, LoggerFixture)
+
+const std::string CONFIG =
+ "logger-name /test/logger \n"
+ "policy \n"
+ "{ \n"
+ " rule \n"
+ " { \n"
+ " id \"Simple Rule\" \n"
+ " for data \n"
+ " checker \n"
+ " { \n"
+ " type customized \n"
+ " sig-type rsa-sha256 \n"
+ " key-locator \n"
+ " { \n"
+ " type name \n"
+ " hyper-relation \n"
+ " { \n"
+ " k-regex ^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$ \n"
+ " k-expand \\\\1\\\\2 \n"
+ " h-relation is-strict-prefix-of \n"
+ " p-regex ^(<>*)$ \n"
+ " p-expand \\\\1 \n"
+ " } \n"
+ " } \n"
+ " } \n"
+ " } \n"
+ "} \n"
+ "validator \n"
+ "{ \n"
+ " rule \n"
+ " { \n"
+ " id \"Request Rule\" \n"
+ " for interest \n"
+ " filter \n"
+ " { \n"
+ " type name \n"
+ " name /test/logger/log \n"
+ " relation is-strict-prefix-of \n"
+ " } \n"
+ " checker \n"
+ " { \n"
+ " type customized \n"
+ " sig-type rsa-sha256 \n"
+ " key-locator \n"
+ " { \n"
+ " type name \n"
+ " regex ^[^<KEY>]*<KEY><>*<><ID-CERT>$ \n"
+ " } \n"
+ " } \n"
+ " } \n"
+ " rule \n"
+ " { \n"
+ " id \"Simple Rule\" \n"
+ " for data \n"
+ " checker \n"
+ " { \n"
+ " type customized \n"
+ " sig-type rsa-sha256 \n"
+ " key-locator \n"
+ " { \n"
+ " type name \n"
+ " hyper-relation \n"
+ " { \n"
+ " k-regex ^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$ \n"
+ " k-expand \\\\1\\\\2 \n"
+ " h-relation is-strict-prefix-of \n"
+ " p-regex ^(<>*)$ \n"
+ " p-expand \\\\1 \n"
+ " } \n"
+ " } \n"
+ " } \n"
+ " } \n"
+ " trust-anchor \n"
+ " { \n"
+ " type file \n"
+ " file-name \"trust-anchor.cert\" \n"
+ " } \n"
+ "} \n";
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+ namespace fs = boost::filesystem;
+
+ fs::create_directory(fs::path(TEST_LOGGER_PATH));
+
+ fs::path configPath = fs::path(TEST_LOGGER_PATH) / "logger-test.conf";
+ std::ofstream os(configPath.c_str());
+ os << CONFIG;
+ os.close();
+
+ Name root("/ndn");
+ addIdentity(root);
+ auto rootCert = m_keyChain.getCertificate(m_keyChain.getDefaultCertificateNameForIdentity(root));
+ fs::path certPath = fs::path(TEST_LOGGER_PATH) / "trust-anchor.cert";
+ ndn::io::save(*rootCert, certPath.string());
+
+ Logger logger(*face1, configPath.string());
+
+ BOOST_CHECK_EQUAL(logger.getLoggerName(), Name("/test/logger"));
+ BOOST_CHECK_EQUAL(logger.getTreePrefix(), Name("/test/logger/tree"));
+ BOOST_CHECK_EQUAL(logger.getLeafPrefix(), Name("/test/logger/leaf"));
+ BOOST_CHECK_EQUAL(logger.getLogPrefix(), Name("/test/logger/log"));
+
+ advanceClocks(time::milliseconds(2), 100);
+
+ Timestamp rootTs = time::toUnixTimestamp(time::system_clock::now()).count() / 1000;
+ NonNegativeInteger rootSeqNo = logger.addSelfSignedCert(*rootCert, rootTs);
+ BOOST_CHECK_EQUAL(rootSeqNo, 0);
+
+ Name leafInterestName("/test/logger/leaf");
+ leafInterestName.appendNumber(0);
+ auto leafInterest = make_shared<Interest>(leafInterestName);
+
+ face1->receive(*leafInterest);
+ advanceClocks(time::milliseconds(2), 100);
+
+ BOOST_CHECK_EQUAL(face1->sentDatas.size(), 1);
+ BOOST_CHECK(leafInterestName.isPrefixOf(face1->sentDatas[0].getName()));
+
+ face1->sentDatas.clear();
+
+ Name treeInterestName("/test/logger/tree");
+ treeInterestName.appendNumber(0);
+ treeInterestName.appendNumber(0);
+ auto treeInterest = make_shared<Interest>(treeInterestName);
+
+ face1->receive(*treeInterest);
+ advanceClocks(time::milliseconds(2), 100);
+
+ BOOST_CHECK_EQUAL(face1->sentDatas.size(), 1);
+ BOOST_CHECK(treeInterestName.isPrefixOf(face1->sentDatas[0].getName()));
+
+ face1->sentDatas.clear();
+
+ Name tld("/ndn/tld");
+ Name tldKeyName = m_keyChain.generateRsaKeyPair(tld);
+ std::vector<ndn::CertificateSubjectDescription> subjectDescription;
+ auto tldCert =
+ m_keyChain.prepareUnsignedIdentityCertificate(tldKeyName, root,
+ time::system_clock::now(),
+ time::system_clock::now() + time::days(1),
+ subjectDescription);
+ m_keyChain.signByIdentity(*tldCert, root);
+ m_keyChain.addCertificate(*tldCert);
+
+ face2->setInterestFilter(tldCert->getName().getPrefix(-1),
+ [&] (const ndn::InterestFilter&, const Interest&) { face2->put(*tldCert); },
+ ndn::RegisterPrefixSuccessCallback(),
+ [] (const Name&, const std::string&) {});
+ advanceClocks(time::milliseconds(2), 100);
+ clear();
+
+ Name logInterestName("/test/logger/log");
+ logInterestName.append(tldCert->getFullName().wireEncode());
+ logInterestName.appendNumber(0);
+ auto logInterest = make_shared<Interest>(logInterestName);
+ m_keyChain.sign(*logInterest, tldCert->getName());
+
+ face1->receive(*logInterest);
+ do {
+ advanceClocks(time::milliseconds(2), 100);
+ } while (passPacket());
+ clear();
+
+ BOOST_CHECK_EQUAL(logger.getDb().getMaxLeafSeq(), 2);
+ auto leafResult1 = logger.getDb().getLeaf(1);
+ BOOST_CHECK(leafResult1.first != nullptr);
+ BOOST_CHECK(leafResult1.second != nullptr);
+
+
+
+ Name leafInterestName2("/test/logger/leaf");
+ leafInterestName2.appendNumber(1);
+ auto leafInterest2 = make_shared<Interest>(leafInterestName2);
+
+ face1->receive(*leafInterest2);
+ advanceClocks(time::milliseconds(2), 100);
+
+ BOOST_CHECK_EQUAL(face1->sentDatas.size(), 1);
+ BOOST_CHECK(leafInterestName2.isPrefixOf(face1->sentDatas[0].getName()));
+ clear();
+
+
+
+ Name treeInterestName2("/test/logger/tree");
+ treeInterestName2.appendNumber(1);
+ treeInterestName2.appendNumber(0);
+ auto treeInterest2 = make_shared<Interest>(treeInterestName2);
+
+ face1->receive(*treeInterest2);
+ advanceClocks(time::milliseconds(2), 100);
+
+ BOOST_CHECK_EQUAL(face1->sentDatas.size(), 1);
+ BOOST_CHECK(treeInterestName2.isPrefixOf(face1->sentDatas[0].getName()));
+ clear();
+
+
+ auto data = make_shared<Data>(Name("/ndn/tld/data"));
+ m_keyChain.sign(*data, tldCert->getName());
+
+ face2->setInterestFilter(data->getName(),
+ [&] (const ndn::InterestFilter&, const Interest&) { face2->put(*data); },
+ ndn::RegisterPrefixSuccessCallback(),
+ [] (const Name&, const std::string&) {});
+ advanceClocks(time::milliseconds(2), 100);
+ clear();
+
+ Name logInterestName2("/test/logger/log");
+ logInterestName2.append(data->getFullName().wireEncode());
+ logInterestName2.appendNumber(1);
+ auto logInterest2 = make_shared<Interest>(logInterestName2);
+ m_keyChain.sign(*logInterest2, tldCert->getName());
+
+ face1->receive(*logInterest2);
+ do {
+ advanceClocks(time::milliseconds(2), 100);
+ } while (passPacket());
+ clear();
+
+ BOOST_CHECK_EQUAL(logger.getDb().getMaxLeafSeq(), 3);
+ auto leafResult2 = logger.getDb().getLeaf(2);
+ BOOST_CHECK(leafResult2.first != nullptr);
+ BOOST_CHECK(leafResult2.second == nullptr);
+
+
+ fs::remove_all(fs::path(TEST_LOGGER_PATH));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace nsl