Fix logic
Change-Id: I7bfb72e8bb245fab3e9a9d575abc7217bbae86d0
diff --git a/src/sync-intro-certificate.h b/obsolete/sync-intro-certificate.h
similarity index 100%
rename from src/sync-intro-certificate.h
rename to obsolete/sync-intro-certificate.h
diff --git a/src/sync-validator.cc b/obsolete/sync-validator.cc
similarity index 100%
rename from src/sync-validator.cc
rename to obsolete/sync-validator.cc
diff --git a/src/sync-validator.h b/obsolete/sync-validator.h
similarity index 100%
rename from src/sync-validator.h
rename to obsolete/sync-validator.h
diff --git a/tests/unit-tests/test-sync-validator.cpp.outdated b/obsolete/tests/test-sync-validator.cpp.outdated
similarity index 100%
rename from tests/unit-tests/test-sync-validator.cpp.outdated
rename to obsolete/tests/test-sync-validator.cpp.outdated
diff --git a/src/logger.hpp b/src/logger.hpp
index 64a8563..c4eee03 100644
--- a/src/logger.hpp
+++ b/src/logger.hpp
@@ -64,7 +64,7 @@
#define _LOG_DEBUG(x) \
std::clog << boost::get_system_time() << " " << boost::this_thread::get_id() << \
- " " << x << std::endl;
+ " " << x << std::endl
#else // _DEBUG
diff --git a/src/logic.cpp b/src/logic.cpp
new file mode 100644
index 0000000..f584da5
--- /dev/null
+++ b/src/logic.cpp
@@ -0,0 +1,593 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012-2014 University of California, Los Angeles
+ *
+ * This file is part of ChronoSync, synchronization library for distributed realtime
+ * applications for NDN.
+ *
+ * ChronoSync 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.
+ *
+ * ChronoSync 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
+ * ChronoSync, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @author Zhenkai Zhu <http://irl.cs.ucla.edu/~zhenkai/>
+ * @author Chaoyi Bian <bcy@pku.edu.cn>
+ * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
+ * @author Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "logic.hpp"
+#include "logger.hpp"
+
+INIT_LOGGER("Logic");
+
+#ifdef _DEBUG
+#define _LOG_DEBUG_ID(v) _LOG_DEBUG("Instance" << m_instanceId << ": " << v)
+#else
+#define _LOG_DEBUG_ID(v) _LOG_DEBUG(v)
+#endif
+
+namespace chronosync {
+
+using ndn::ConstBufferPtr;
+using ndn::EventId;
+
+const uint8_t EMPTY_DIGEST_VALUE[] = {
+ 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
+ 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+ 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
+ 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55
+};
+
+#ifdef _DEBUG
+int Logic::m_instanceCounter = 0;
+#endif
+
+const time::steady_clock::Duration Logic::DEFAULT_RESET_TIMER = time::seconds(0);
+const time::steady_clock::Duration Logic::DEFAULT_CANCEL_RESET_TIMER = time::milliseconds(500);
+const time::milliseconds Logic::DEFAULT_RESET_INTEREST_LIFETIME(1000);
+const time::milliseconds Logic::DEFAULT_SYNC_INTEREST_LIFETIME(1000);
+const time::milliseconds Logic::DEFAULT_SYNC_REPLY_FRESHNESS(1000);
+
+const ndn::ConstBufferPtr Logic::EMPTY_DIGEST(new ndn::Buffer(EMPTY_DIGEST_VALUE, 32));
+const ndn::name::Component Logic::RESET_COMPONENT("reset");
+
+Logic::Logic(ndn::Face& face,
+ const Name& syncPrefix,
+ const Name& userPrefix,
+ const UpdateCallback& onUpdate,
+ const time::steady_clock::Duration& resetTimer,
+ const time::steady_clock::Duration& cancelResetTimer,
+ const time::milliseconds& resetInterestLifetime,
+ const time::milliseconds& syncInterestLifetime,
+ const time::milliseconds& syncReplyFreshness)
+ : m_face(face)
+ , m_syncPrefix(syncPrefix)
+ , m_userPrefix(userPrefix)
+ , m_interestTable(m_face.getIoService())
+ , m_outstandingInterestId(0)
+ , m_isInReset(false)
+ , m_needPeriodReset(resetTimer > time::steady_clock::Duration::zero())
+ , m_onUpdate(onUpdate)
+ , m_scheduler(m_face.getIoService())
+ , m_randomGenerator(static_cast<unsigned int>(std::time(0)))
+ , m_rangeUniformRandom(m_randomGenerator, boost::uniform_int<>(100,500))
+ , m_reexpressionJitter(m_randomGenerator, boost::uniform_int<>(100,500))
+ , m_resetTimer(resetTimer)
+ , m_cancelResetTimer(cancelResetTimer)
+ , m_resetInterestLifetime(resetInterestLifetime)
+ , m_syncInterestLifetime(syncInterestLifetime)
+ , m_syncReplyFreshness(syncReplyFreshness)
+{
+#ifdef _DEBUG
+ m_instanceId = m_instanceCounter++;
+#endif
+
+ _LOG_DEBUG_ID(">> Logic::Logic");
+
+ m_syncReset = m_syncPrefix;
+ m_syncReset.append("reset");
+
+ _LOG_DEBUG_ID("Listen to: " << m_syncPrefix);
+ m_syncRegisteredPrefixId =
+ m_face.setInterestFilter(m_syncPrefix,
+ bind(&Logic::onSyncInterest, this, _1, _2),
+ bind(&Logic::onSyncRegisterFailed, this, _1, _2));
+
+ setUserPrefix(m_userPrefix);
+
+ _LOG_DEBUG_ID("<< Logic::Logic");
+}
+
+Logic::~Logic()
+{
+ m_face.unsetInterestFilter(m_syncRegisteredPrefixId);
+ m_scheduler.cancelAllEvents();
+}
+
+void
+Logic::reset()
+{
+ m_isInReset = true;
+
+ m_state.reset();
+ m_log.clear();
+
+ sendResetInterest();
+
+ // reset outstanding interest name, so that data for previous interest will be dropped.
+ if (m_outstandingInterestId != 0) {
+ m_face.removePendingInterest(m_outstandingInterestId);
+ m_outstandingInterestId = 0;
+ }
+
+ sendSyncInterest();
+
+ if (static_cast<bool>(m_delayedInterestProcessingId))
+ m_scheduler.cancelEvent(m_delayedInterestProcessingId);
+
+ m_delayedInterestProcessingId =
+ m_scheduler.scheduleEvent(m_cancelResetTimer,
+ bind(&Logic::cancelReset, this));
+}
+
+void
+Logic::setUserPrefix(const Name& userPrefix)
+{
+ m_userPrefix = userPrefix;
+
+ m_sessionName = m_userPrefix;
+ m_sessionName.appendNumber(ndn::time::toUnixTimestamp(ndn::time::system_clock::now()).count());
+
+ m_seqNo = 0;
+
+ reset();
+}
+
+void
+Logic::updateSeqNo(const SeqNo& seqNo)
+{
+ _LOG_DEBUG_ID(">> Logic::updateSeqNo");
+ _LOG_DEBUG_ID("seqNo: " << seqNo << " m_seqNo: " << m_seqNo);
+ if (seqNo < m_seqNo || seqNo == 0)
+ return;
+
+ m_seqNo = seqNo;
+
+ _LOG_DEBUG_ID("updateSeqNo: m_seqNo " << m_seqNo);
+
+ if (!m_isInReset) {
+ _LOG_DEBUG_ID("updateSeqNo: not in Reset ");
+ ndn::ConstBufferPtr previousRoot = m_state.getRootDigest();
+ {
+ using namespace CryptoPP;
+
+ std::string hash;
+ StringSource(previousRoot->buf(), previousRoot->size(), true,
+ new HexEncoder(new StringSink(hash), false));
+ _LOG_DEBUG_ID("Hash: " << hash);
+ }
+
+ bool isInserted = false;
+ bool isUpdated = false;
+ SeqNo oldSeq;
+ boost::tie(isInserted, isUpdated, oldSeq) = m_state.update(m_sessionName, seqNo);
+
+ _LOG_DEBUG_ID("Insert: " << std::boolalpha << isInserted);
+ _LOG_DEBUG_ID("Updated: " << std::boolalpha << isUpdated);
+ if (isInserted || isUpdated) {
+ DiffStatePtr commit = make_shared<DiffState>();
+ commit->update(m_sessionName, seqNo);
+ commit->setRootDigest(m_state.getRootDigest());
+ insertToDiffLog(commit, previousRoot);
+
+ satisfyPendingSyncInterests(commit);
+ }
+ }
+}
+
+ConstBufferPtr
+Logic::getRootDigest() const
+{
+ return m_state.getRootDigest();
+}
+
+void
+Logic::printState(std::ostream& os) const
+{
+ BOOST_FOREACH(ConstLeafPtr leaf, m_state.getLeaves())
+ {
+ os << *leaf << "\n";
+ }
+}
+
+std::set<Name>
+Logic::getSessionNames() const
+{
+ std::set<Name> sessionNames;
+
+ BOOST_FOREACH(ConstLeafPtr leaf, m_state.getLeaves())
+ {
+ sessionNames.insert(leaf->getSessionName());
+ }
+
+ return sessionNames;
+}
+
+void
+Logic::onSyncInterest(const Name& prefix, const Interest& interest)
+{
+ _LOG_DEBUG_ID(">> Logic::onSyncInterest");
+ Name name = interest.getName();
+
+ _LOG_DEBUG_ID("InterestName: " << name);
+
+ if (RESET_COMPONENT != name.get(-1)) {
+ // normal sync interest
+ processSyncInterest(interest.shared_from_this());
+ }
+ else
+ // reset interest
+ processResetInterest(interest);
+
+ _LOG_DEBUG_ID("<< Logic::onSyncInterest");
+}
+
+void
+Logic::onSyncRegisterFailed(const Name& prefix, const std::string& msg)
+{
+ //Sync prefix registration failed
+ _LOG_DEBUG_ID(">> Logic::onSyncRegisterFailed");
+}
+
+void
+Logic::onSyncData(const Interest& interest, Data& data)
+{
+ _LOG_DEBUG_ID(">> Logic::onSyncData");
+ // Place holder for validator.
+ onSyncDataValidated(data.shared_from_this());
+ _LOG_DEBUG_ID("<< Logic::onSyncData");
+}
+
+void
+Logic::onResetData(const Interest& interest, Data& data)
+{
+ // This should not happened, drop the received data.
+}
+
+void
+Logic::onSyncTimeout(const Interest& interest)
+{
+ // It is OK. Others will handle the time out situation.
+ _LOG_DEBUG_ID(">> Logic::onSyncTimeout");
+ _LOG_DEBUG_ID("Interest: " << interest.getName());
+ _LOG_DEBUG_ID("<< Logic::onSyncTimeout");
+}
+
+void
+Logic::onSyncDataValidationFailed(const shared_ptr<const Data>& data)
+{
+ // SyncReply cannot be validated.
+}
+
+void
+Logic::onSyncDataValidated(const shared_ptr<const Data>& data)
+{
+ Name name = data->getName();
+ ConstBufferPtr digest = make_shared<ndn::Buffer>(name.get(-1).value(), name.get(-1).value_size());
+
+ processSyncData(name, digest, data->getContent().blockFromValue());
+}
+
+void
+Logic::processSyncInterest(const shared_ptr<const Interest>& interest,
+ bool isTimedProcessing/*=false*/)
+{
+ _LOG_DEBUG_ID(">> Logic::processSyncInterest");
+
+ const Name& name = interest->getName();
+ ConstBufferPtr digest =
+ make_shared<ndn::Buffer>(name.get(-1).value(), name.get(-1).value_size());
+
+ ConstBufferPtr rootDigest = m_state.getRootDigest();
+
+ // If the digest of the incoming interest is the same as root digest
+ // Put the interest into InterestTable
+ if (*rootDigest == *digest) {
+ _LOG_DEBUG_ID("Oh, we are in the same state");
+ m_interestTable.insert(interest, digest, false);
+
+ if (!m_isInReset)
+ return;
+
+ if (!isTimedProcessing) {
+ _LOG_DEBUG_ID("Non timed processing in reset");
+ // Still in reset, our own seq has not been put into state yet
+ // Do not hurry, some others may be also resetting and may send their reply
+ if (static_cast<bool>(m_delayedInterestProcessingId))
+ m_scheduler.cancelEvent(m_delayedInterestProcessingId);
+
+ time::milliseconds after(m_rangeUniformRandom());
+ _LOG_DEBUG_ID("After: " << after);
+ m_delayedInterestProcessingId =
+ m_scheduler.scheduleEvent(after,
+ bind(&Logic::processSyncInterest, this, interest, true));
+ }
+ else {
+ _LOG_DEBUG_ID("Timed processing in reset");
+ // Now we can get out of reset state by putting our own stuff into m_state.
+ cancelReset();
+ }
+
+ return;
+ }
+
+ // If the digest of incoming interest is an "empty" digest
+ if (digest == EMPTY_DIGEST) {
+ _LOG_DEBUG_ID("Poor guy, he knows nothing");
+ sendSyncData(name, m_state);
+ return;
+ }
+
+ DiffStateContainer::iterator stateIter = m_log.find(digest);
+ // If the digest of incoming interest can be found from the log
+ if (stateIter != m_log.end()) {
+ _LOG_DEBUG_ID("It is ok, you are so close");
+ sendSyncData(name, *(*stateIter)->diff());
+ return;
+ }
+
+ if (!isTimedProcessing) {
+ _LOG_DEBUG_ID("Let's wait, just wait for a while");
+ // Do not hurry, some incoming SyncReplies may help us to recognize the digest
+ bool doesExist = m_interestTable.insert(interest, digest, true);
+ if (doesExist)
+ // Original comment (not sure): somebody else replied, so restart random-game timer
+ // YY: Get the same SyncInterest again, refresh the timer
+ m_scheduler.cancelEvent(m_delayedInterestProcessingId);
+
+ m_delayedInterestProcessingId =
+ m_scheduler.scheduleEvent(time::milliseconds(m_rangeUniformRandom()),
+ bind(&Logic::processSyncInterest, this, interest, true));
+ }
+ else {
+ // OK, nobody is helping us, just tell the truth.
+ _LOG_DEBUG_ID("OK, nobody is helping us, just tell the truth");
+ m_interestTable.erase(digest);
+ sendSyncData(name, m_state);
+ }
+
+ _LOG_DEBUG_ID("<< Logic::processSyncInterest");
+}
+
+void
+Logic::processResetInterest(const Interest& interest)
+{
+ _LOG_DEBUG_ID(">> Logic::processResetInterest");
+ reset();
+}
+
+void
+Logic::processSyncData(const Name& name,
+ ndn::ConstBufferPtr digest,
+ const Block& syncReplyBlock)
+{
+ _LOG_DEBUG_ID(">> Logic::processSyncData");
+
+ DiffStatePtr commit = make_shared<DiffState>();
+ ndn::ConstBufferPtr previousRoot = m_state.getRootDigest();
+
+ try {
+ m_interestTable.erase(digest); // Remove satisfied interest from PIT
+
+ State reply;
+ reply.wireDecode(syncReplyBlock);
+
+ std::vector<MissingDataInfo> v;
+ BOOST_FOREACH(ConstLeafPtr leaf, reply.getLeaves().get<ordered>())
+ {
+ BOOST_ASSERT(leaf != 0);
+
+ const Name& info = leaf->getSessionName();
+ SeqNo seq = leaf->getSeq();
+
+ bool isInserted = false;
+ bool isUpdated = false;
+ SeqNo oldSeq;
+ boost::tie(isInserted, isUpdated, oldSeq) = m_state.update(info, seq);
+
+ if (isInserted || isUpdated) {
+ commit->update(info, seq);
+
+ oldSeq++;
+ MissingDataInfo mdi = {info, oldSeq, seq};
+ v.push_back(mdi);
+ }
+ }
+
+ if (!v.empty()) {
+ m_onUpdate(v);
+
+ commit->setRootDigest(m_state.getRootDigest());
+ insertToDiffLog(commit, previousRoot);
+ }
+ else {
+ _LOG_DEBUG_ID("What? nothing new");
+ }
+ }
+ catch (State::Error&) {
+ _LOG_DEBUG_ID("Something really fishy happened during state decoding");
+ // Something really fishy happened during state decoding;
+ commit.reset();
+ return;
+ }
+
+ if (static_cast<bool>(commit) && !commit->getLeaves().empty()) {
+ // state changed and it is safe to express a new interest
+ time::steady_clock::Duration after = time::milliseconds(m_reexpressionJitter());
+ _LOG_DEBUG_ID("Reschedule sync interest after: " << after);
+ EventId eventId = m_scheduler.scheduleEvent(after,
+ bind(&Logic::sendSyncInterest, this));
+
+ m_scheduler.cancelEvent(m_reexpressingInterestId);
+ m_reexpressingInterestId = eventId;
+ }
+}
+
+void
+Logic::satisfyPendingSyncInterests(ConstDiffStatePtr commit)
+{
+ _LOG_DEBUG_ID(">> Logic::satisfyPendingSyncInterests");
+ try {
+ _LOG_DEBUG_ID("InterestTable size: " << m_interestTable.size());
+ for (InterestTable::const_iterator it = m_interestTable.begin();
+ it != m_interestTable.end(); it++) {
+ ConstUnsatisfiedInterestPtr request = *it;
+
+ if (request->isUnknown)
+ sendSyncData(request->interest->getName(), m_state);
+ else
+ sendSyncData(request->interest->getName(), *commit);
+ }
+ m_interestTable.clear();
+ }
+ catch (InterestTable::Error&) {
+ // ok. not really an error
+ }
+ _LOG_DEBUG_ID("<< Logic::satisfyPendingSyncInterests");
+}
+
+void
+Logic::insertToDiffLog(DiffStatePtr commit, ndn::ConstBufferPtr previousRoot)
+{
+ _LOG_DEBUG_ID(">> Logic::insertToDiffLog");
+ // Connect to the history
+ if (!m_log.empty())
+ (*m_log.find(previousRoot))->setNext(commit);
+
+ // Insert the commit
+ m_log.erase(commit->getRootDigest());
+ m_log.insert(commit);
+ _LOG_DEBUG_ID("<< Logic::insertToDiffLog");
+}
+
+void
+Logic::sendResetInterest()
+{
+ _LOG_DEBUG_ID(">> Logic::sendResetInterest");
+
+ if (m_needPeriodReset) {
+ _LOG_DEBUG_ID("Need Period Reset");
+ _LOG_DEBUG_ID("ResetTimer: " << m_resetTimer);
+
+ EventId eventId =
+ m_scheduler.scheduleEvent(m_resetTimer + ndn::time::milliseconds(m_reexpressionJitter()),
+ bind(&Logic::sendResetInterest, this));
+ m_scheduler.cancelEvent(m_resetInterestId);
+ m_resetInterestId = eventId;
+ }
+
+ Interest interest(m_syncReset);
+ interest.setMustBeFresh(true);
+ interest.setInterestLifetime(m_resetInterestLifetime);
+ m_face.expressInterest(interest,
+ bind(&Logic::onResetData, this, _1, _2),
+ bind(&Logic::onSyncTimeout, this, _1));
+
+ _LOG_DEBUG_ID("<< Logic::sendResetInterest");
+}
+
+void
+Logic::sendSyncInterest()
+{
+ _LOG_DEBUG_ID(">> Logic::sendSyncInterest");
+
+ Name interestName;
+ interestName.append(m_syncPrefix)
+ .append(ndn::name::Component(*m_state.getRootDigest()));
+
+ m_outstandingInterestName = interestName;
+
+#ifdef _DEBUG
+ printDigest(m_state.getRootDigest());
+#endif
+
+ EventId eventId =
+ m_scheduler.scheduleEvent(m_syncInterestLifetime +
+ ndn::time::milliseconds(m_reexpressionJitter()),
+ bind(&Logic::sendSyncInterest, this));
+ m_scheduler.cancelEvent(m_reexpressingInterestId);
+ m_reexpressingInterestId = eventId;
+
+ Interest interest(interestName);
+ interest.setMustBeFresh(true);
+ interest.setInterestLifetime(m_syncInterestLifetime);
+
+ m_outstandingInterestId = m_face.expressInterest(interest,
+ bind(&Logic::onSyncData, this, _1, _2),
+ bind(&Logic::onSyncTimeout, this, _1));
+
+ _LOG_DEBUG_ID("Send interest: " << interest.getName());
+ _LOG_DEBUG_ID("<< Logic::sendSyncInterest");
+}
+
+void
+Logic::sendSyncData(const Name& name, const State& state)
+{
+ _LOG_DEBUG_ID(">> Logic::sendSyncData");
+ shared_ptr<Data> syncReply = make_shared<Data>(name);
+ syncReply->setContent(state.wireEncode());
+ syncReply->setFreshnessPeriod(m_syncReplyFreshness);
+ m_keyChain.sign(*syncReply);
+
+ m_face.put(*syncReply);
+
+ // checking if our own interest got satisfied
+ if (m_outstandingInterestName == name) {
+ // remove outstanding interest
+ if (m_outstandingInterestId != 0) {
+ m_face.removePendingInterest(m_outstandingInterestId);
+ m_outstandingInterestId = 0;
+ }
+
+ // re-schedule sending Sync interest
+ time::milliseconds after(m_reexpressionJitter());
+ _LOG_DEBUG_ID("Satisfy our own interest");
+ _LOG_DEBUG_ID("Reschedule sync interest after " << after);
+ EventId eventId = m_scheduler.scheduleEvent(after, bind(&Logic::sendSyncInterest, this));
+ m_scheduler.cancelEvent(m_reexpressingInterestId);
+ m_reexpressingInterestId = eventId;
+ }
+ _LOG_DEBUG_ID("<< Logic::sendSyncData");
+}
+
+void
+Logic::cancelReset()
+{
+ _LOG_DEBUG_ID(">> Logic::cancelReset");
+ if (!m_isInReset)
+ return;
+
+ m_isInReset = false;
+ updateSeqNo(m_seqNo);
+ _LOG_DEBUG_ID("<< Logic::cancelReset");
+}
+
+void
+Logic::printDigest(ndn::ConstBufferPtr digest)
+{
+ using namespace CryptoPP;
+
+ std::string hash;
+ StringSource(digest->buf(), digest->size(), true,
+ new HexEncoder(new StringSink(hash), false));
+ _LOG_DEBUG_ID("Hash: " << hash);
+}
+
+} // namespace chronosync
diff --git a/src/logic.hpp b/src/logic.hpp
new file mode 100644
index 0000000..2be8636
--- /dev/null
+++ b/src/logic.hpp
@@ -0,0 +1,388 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012-2014 University of California, Los Angeles
+ *
+ * This file is part of ChronoSync, synchronization library for distributed realtime
+ * applications for NDN.
+ *
+ * ChronoSync 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.
+ *
+ * ChronoSync 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
+ * ChronoSync, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @author Zhenkai Zhu <http://irl.cs.ucla.edu/~zhenkai/>
+ * @author Chaoyi Bian <bcy@pku.edu.cn>
+ * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
+ * @author Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef CHRONOSYNC_LOGIC_HPP
+#define CHRONOSYNC_LOGIC_HPP
+
+#include "boost-header.h"
+#include <memory>
+#include <map>
+
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/util/scheduler.hpp>
+#include <ndn-cxx/security/key-chain.hpp>
+
+#include "interest-table.hpp"
+#include "diff-state-container.hpp"
+
+namespace chronosync {
+
+/**
+ * @brief The missing sequence numbers for a session
+ *
+ * This class is used to notify the clients of Logic
+ * the details of state changes.
+ *
+ * Instances of this class is usually used as elements of some containers
+ * such as std::vector, thus it is copyable.
+ */
+class MissingDataInfo
+{
+public:
+ /// @brief session name
+ Name session;
+ /// @brief the lowest one of missing sequence numbers
+ SeqNo low;
+ /// @brief the highest one of missing sequence numbers
+ SeqNo high;
+};
+
+/**
+ * @brief The callback function to handle state updates
+ *
+ * The parameter is a set of MissingDataInfo, of which each corresponds to
+ * a session that has changed its state.
+ */
+typedef function<void(const std::vector<MissingDataInfo>&)> UpdateCallback;
+
+/**
+ * @brief Logic of ChronoSync
+ */
+class Logic : noncopyable
+{
+public:
+ static const time::steady_clock::Duration DEFAULT_RESET_TIMER;
+ static const time::steady_clock::Duration DEFAULT_CANCEL_RESET_TIMER;
+ static const time::milliseconds DEFAULT_RESET_INTEREST_LIFETIME;
+ static const time::milliseconds DEFAULT_SYNC_INTEREST_LIFETIME;
+ static const time::milliseconds DEFAULT_SYNC_REPLY_FRESHNESS;
+
+ /**
+ * @brief Constructor
+ *
+ * @param syncPrefix The prefix of the sync group
+ * @param userPrefix The prefix of the user who owns the session
+ * @param onUpdate The callback function to handle state updates
+ * @param resetTimer The timer to periodically send Reset Interest
+ * @param syncReplyFreshness The FreshnessPeriod of sync reply
+ * @param resetInterestLifetime The lifetime of sync interest
+ * @param resetInterestLifetime The lifetime of Reset Interest
+ * @param cancelResetTimer The timer to exit from Reset state
+ */
+ Logic(ndn::Face& face,
+ const Name& syncPrefix,
+ const Name& userPrefix,
+ const UpdateCallback& onUpdate,
+ const time::steady_clock::Duration& resetTimer = DEFAULT_RESET_TIMER,
+ const time::steady_clock::Duration& cancelResetTimer = DEFAULT_CANCEL_RESET_TIMER,
+ const time::milliseconds& resetInterestLifetime = DEFAULT_RESET_INTEREST_LIFETIME,
+ const time::milliseconds& syncInterestLifetime = DEFAULT_SYNC_INTEREST_LIFETIME,
+ const time::milliseconds& syncReplyFreshness = DEFAULT_SYNC_REPLY_FRESHNESS);
+
+ ~Logic();
+
+ /// @brief Reset the sync tree (and restart synchronization again)
+ void
+ reset();
+
+ /**
+ * @brief Set user prefix
+ *
+ * This method will also change the session name and trigger reset.
+ *
+ * @param userPrefix The prefix of user.
+ */
+ void
+ setUserPrefix(const Name& userPrefix);
+
+ /// @brief Get the name of the local session.
+ const Name&
+ getSessionName() const
+ {
+ return m_sessionName;
+ }
+
+ /// @brief Get current seqNo of the local session.
+ const SeqNo&
+ getSeqNo() const
+ {
+ return m_seqNo;
+ }
+
+ /**
+ * @brief Update the seqNo of the local session
+ *
+ * The method updates the existing seqNo with the supplied seqNo.
+ *
+ * @param seq The new seqNo.
+ */
+ void
+ updateSeqNo(const SeqNo& seq);
+
+ /// @brief Get root digest of current sync tree
+ ndn::ConstBufferPtr
+ getRootDigest() const;
+
+ /// @brief Get the name of all sessions
+ std::set<Name>
+ getSessionNames() const;
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+ void
+ printState(std::ostream& os) const;
+
+ ndn::Scheduler&
+ getScheduler()
+ {
+ return m_scheduler;
+ }
+
+ State&
+ getState()
+ {
+ return m_state;
+ }
+
+private:
+ /**
+ * @brief Callback to handle Sync Interest
+ *
+ * This method checks whether an incoming interest is a normal one or a reset
+ * and dispatches the incoming interest to corresponding processing methods.
+ *
+ * @param prefix The prefix of the sync group.
+ * @param interest The incoming sync interest.
+ */
+ void
+ onSyncInterest(const Name& prefix, const Interest& interest);
+
+ /**
+ * @brief Callback to handle Sync prefix registration failure
+ *
+ * This method does nothing for now.
+ *
+ * @param prefix The prefix of the sync group.
+ * @param msg The error message.
+ */
+ void
+ onSyncRegisterFailed(const Name& prefix, const std::string& msg);
+
+ /**
+ * @brief Callback to handle Sync Reply
+ *
+ * This method calls validator to validate Sync Reply.
+ * For now, validation is disabled, Logic::onSyncDataValidated is called
+ * directly.
+ *
+ * @param interest The Sync Interest
+ * @param data The reply to the Sync Interest
+ */
+ void
+ onSyncData(const Interest& interest, Data& data);
+
+ /**
+ * @brief Callback to handle reply to Reset Interest.
+ *
+ * This method does nothing, since reply to Reset Interest is not useful for now.
+ *
+ * @param interest The Reset Interest
+ * @param data The reply to the Reset Interest
+ */
+ void
+ onResetData(const Interest& interest, Data& data);
+
+ /**
+ * @brief Callback to handle Sync Interest timeout.
+ *
+ * This method does nothing, since Logic per se handles timeout explicitly.
+ *
+ * @param interest The Sync Interest
+ */
+ void
+ onSyncTimeout(const Interest& interest);
+
+ /**
+ * @brief Callback to invalid Sync Reply.
+ *
+ * This method does nothing but drops the invalid reply.
+ *
+ * @param data The invalid Sync Reply
+ */
+ void
+ onSyncDataValidationFailed(const shared_ptr<const Data>& data);
+
+ /**
+ * @brief Callback to valid Sync Reply.
+ *
+ * This method simply passes the valid reply to processSyncData.
+ *
+ * @param data The valid Sync Reply.
+ */
+ void
+ onSyncDataValidated(const shared_ptr<const Data>& data);
+
+ /**
+ * @brief Process normal Sync Interest
+ *
+ * This method extracts the digest from the incoming Sync Interest,
+ * compares it against current local digest, and process the Sync
+ * Interest according to the comparison result. See docs/design.rst
+ * for more details.
+ *
+ * @param interest The incoming interest
+ * @param isTimedProcessing True if the interest needs an immediate reply,
+ * otherwise hold the interest for a while before
+ * making a reply (to avoid unnecessary recovery)
+ */
+ void
+ processSyncInterest(const shared_ptr<const Interest>& interest,
+ bool isTimedProcessing = false);
+
+ /**
+ * @brief Process reset Sync Interest
+ *
+ * This method simply call Logic::reset()
+ *
+ * @param interest The incoming interest.
+ */
+ void
+ processResetInterest(const Interest& interest);
+
+ /**
+ * @brief Process Sync Reply.
+ *
+ * This method extracts state update information from Sync Reply and applies
+ * it to the Sync Tree and re-express Sync Interest.
+ *
+ * @param name The data name of the Sync Reply.
+ * @param digest The digest in the data name.
+ * @param syncReplyBlock The content of the Sync Reply.
+ */
+ void
+ processSyncData(const Name& name,
+ ndn::ConstBufferPtr digest,
+ const Block& syncReplyBlock);
+
+ /**
+ * @brief Insert state diff into log
+ *
+ * @param diff The diff .
+ * @param previousRoot The root digest before state changes.
+ */
+ void
+ insertToDiffLog(DiffStatePtr diff,
+ ndn::ConstBufferPtr previousRoot);
+
+ /**
+ * @brief Reply to all pending Sync Interests with a particular commit (or diff)
+ *
+ * @param commit The diff.
+ */
+ void
+ satisfyPendingSyncInterests(ConstDiffStatePtr commit);
+
+ /// @brief Helper method to send normal Sync Interest
+ void
+ sendSyncInterest();
+
+ /// @brief Helper method to send reset Sync Interest
+ void
+ sendResetInterest();
+
+ /// @brief Helper method to send Sync Reply
+ void
+ sendSyncData(const Name& name, const State& state);
+
+ /**
+ * @brief Unset reset status
+ *
+ * By invoking this method, one can add its own state into the Sync Tree, thus
+ * jumping out of the reset status
+ */
+ void
+ cancelReset();
+
+ void
+ printDigest(ndn::ConstBufferPtr digest);
+
+private:
+
+ static const ndn::ConstBufferPtr EMPTY_DIGEST;
+ static const ndn::name::Component RESET_COMPONENT;
+
+ // Communication
+ ndn::Face& m_face;
+ Name m_syncPrefix;
+ const ndn::RegisteredPrefixId* m_syncRegisteredPrefixId;
+ Name m_syncReset;
+ Name m_userPrefix;
+
+ // State
+ Name m_sessionName;
+ SeqNo m_seqNo;
+ State m_state;
+ DiffStateContainer m_log;
+ InterestTable m_interestTable;
+ Name m_outstandingInterestName;
+ const ndn::PendingInterestId* m_outstandingInterestId;
+ bool m_isInReset;
+ bool m_needPeriodReset;
+
+ // Callback
+ UpdateCallback m_onUpdate;
+
+ // Event
+ ndn::Scheduler m_scheduler;
+ ndn::EventId m_delayedInterestProcessingId;
+ ndn::EventId m_reexpressingInterestId;
+ ndn::EventId m_resetInterestId;
+
+ // Timer
+ boost::mt19937 m_randomGenerator;
+ boost::variate_generator<boost::mt19937&, boost::uniform_int<> > m_rangeUniformRandom;
+ boost::variate_generator<boost::mt19937&, boost::uniform_int<> > m_reexpressionJitter;
+ /// @brief Timer to send next reset 0 for no reset
+ time::steady_clock::Duration m_resetTimer;
+ /// @brief Timer to cancel reset state
+ time::steady_clock::Duration m_cancelResetTimer;
+ /// @brief Lifetime of reset interest
+ time::milliseconds m_resetInterestLifetime;
+ /// @brief Lifetime of sync interest
+ time::milliseconds m_syncInterestLifetime;
+ /// @brief FreshnessPeriod of SyncReply
+ time::milliseconds m_syncReplyFreshness;
+
+ // Others
+ ndn::KeyChain m_keyChain;
+
+#ifdef _DEBUG
+ int m_instanceId;
+ static int m_instanceCounter;
+#endif
+};
+
+
+} // namespace chronosync
+
+#endif // CHRONOSYNC_LOGIC_HPP
diff --git a/src/sync-event.h b/src/sync-event.h
deleted file mode 100644
index bbe07bc..0000000
--- a/src/sync-event.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2012-2014 University of California, Los Angeles
- *
- * This file is part of ChronoSync, synchronization library for distributed realtime
- * applications for NDN.
- *
- * ChronoSync 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.
- *
- * ChronoSync 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
- * ChronoSync, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- *
- * @author Zhenkai Zhu <http://irl.cs.ucla.edu/~zhenkai/>
- * @author Chaoyi Bian <bcy@pku.edu.cn>
- * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
- */
-
-#ifndef SYNC_EVENT_H
-#define SYNC_EVENT_H
-
-#include <boost/function.hpp>
-
-namespace Sync
-{
-
-typedef boost::function< void ( ) > Event;
-
-} // Sync
-
-#endif // SYNC_EVENT_H
diff --git a/src/sync-logic-event-container.h b/src/sync-logic-event-container.h
deleted file mode 100644
index 015984d..0000000
--- a/src/sync-logic-event-container.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2012-2014 University of California, Los Angeles
- *
- * This file is part of ChronoSync, synchronization library for distributed realtime
- * applications for NDN.
- *
- * ChronoSync 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.
- *
- * ChronoSync 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
- * ChronoSync, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- *
- * @author Zhenkai Zhu <http://irl.cs.ucla.edu/~zhenkai/>
- * @author Chaoyi Bian <bcy@pku.edu.cn>
- * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
- */
-
-#ifndef SYNC_LOGIC_EVENT_CONTAINER_H
-#define SYNC_LOGIC_EVENT_CONTAINER_H
-
-#include "sync-event.h"
-
-#include <boost/function.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include <boost/multi_index_container.hpp>
-// #include <boost/multi_index/tag.hpp>
-#include <boost/multi_index/ordered_index.hpp>
-// #include <boost/multi_index/composite_key.hpp>
-// #include <boost/multi_index/hashed_index.hpp>
-// #include <boost/multi_index/random_access_index.hpp>
-#include <boost/multi_index/member.hpp>
-// #include <boost/multi_index/mem_fun.hpp>
-
-namespace mi = boost::multi_index;
-
-namespace Sync
-{
-
-struct LogicEvent
-{
- LogicEvent (const boost::system_time &_time, Event _event, uint32_t _label)
- : time (_time)
- , event (_event)
- , lbl (_label)
- { }
-
- boost::system_time time;
- Event event;
- uint32_t lbl;
-};
-
-/// @cond include_hidden
-struct byLabel { } ;
-/// @endcond
-
-/**
- * \ingroup sync
- * @brief ???
- */
-struct EventsContainer : public mi::multi_index_container<
- LogicEvent,
- mi::indexed_by<
-
- mi::ordered_non_unique<
- mi::member<LogicEvent, boost::system_time, &LogicEvent::time>
- >,
-
- mi::ordered_non_unique<
- mi::tag<byLabel>,
- mi::member<LogicEvent, uint32_t, &LogicEvent::lbl>
- >
- >
- >
-{
-};
-
-} // Sync
-
-#endif // SYNC_LOGIC_EVENT_CONTAINER_H
diff --git a/src/sync-logic.cc b/src/sync-logic.cc
deleted file mode 100644
index 0567b60..0000000
--- a/src/sync-logic.cc
+++ /dev/null
@@ -1,714 +0,0 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2012-2014 University of California, Los Angeles
- *
- * This file is part of ChronoSync, synchronization library for distributed realtime
- * applications for NDN.
- *
- * ChronoSync 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.
- *
- * ChronoSync 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
- * ChronoSync, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- *
- * @author Zhenkai Zhu <http://irl.cs.ucla.edu/~zhenkai/>
- * @author Chaoyi Bian <bcy@pku.edu.cn>
- * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
- * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/web/index.html>
- */
-
-#include "sync-logic.h"
-#include "sync-diff-leaf.h"
-#include "sync-full-leaf.h"
-#include "sync-logging.h"
-#include "sync-state.h"
-
-#include <boost/foreach.hpp>
-#include <boost/lexical_cast.hpp>
-#include <vector>
-
-using namespace ndn;
-
-INIT_LOGGER ("SyncLogic")
-
-
-#ifdef _DEBUG
-#define _LOG_DEBUG_ID(v) _LOG_DEBUG(m_instanceId << " " << v)
-#else
-#define _LOG_DEBUG_ID(v) _LOG_DEBUG(v)
-#endif
-
-#define GET_RANDOM(var) var ()
-
-#define TIME_SECONDS_WITH_JITTER(sec) \
- (time::seconds(sec) + time::milliseconds(GET_RANDOM (m_reexpressionJitter)))
-
-#define TIME_MILLISECONDS_WITH_JITTER(ms) \
- (time::milliseconds(ms) + time::milliseconds(GET_RANDOM (m_reexpressionJitter)))
-
-namespace Sync {
-
-using ndn::shared_ptr;
-
-int SyncLogic::m_instanceCounter = 0;
-
-const int SyncLogic::m_syncResponseFreshness = 1000; // MUST BE dividable by 1000!!!
-const int SyncLogic::m_syncInterestReexpress = 4; // seconds
-
-SyncLogic::SyncLogic (const Name& syncPrefix,
- const IdentityCertificate& myCertificate,
- shared_ptr<Validator> validator,
- shared_ptr<Face> face,
- LogicUpdateCallback onUpdate,
- LogicRemoveCallback onRemove)
- : m_state (new FullState)
- , m_syncInterestTable (face->getIoService(), time::seconds(m_syncInterestReexpress))
- , m_syncPrefix (syncPrefix)
- , m_myCertificate(myCertificate)
- , m_onUpdate (onUpdate)
- , m_onRemove (onRemove)
- , m_perBranch (false)
- , m_validator(validator)
- , m_face(face)
- , m_scheduler(face->getIoService())
- , m_randomGenerator (static_cast<unsigned int> (std::time (0)))
- , m_rangeUniformRandom (m_randomGenerator, boost::uniform_int<> (200,1000))
- , m_reexpressionJitter (m_randomGenerator, boost::uniform_int<> (100,500))
- , m_recoveryRetransmissionInterval (m_defaultRecoveryRetransmitInterval)
-{
- m_syncRegisteredPrefixId = m_face->setInterestFilter (m_syncPrefix,
- bind(&SyncLogic::onSyncInterest, this, _1, _2),
- bind(&SyncLogic::onSyncRegisterFailed, this, _1, _2));
-
-
- m_reexpressingInterestId = m_scheduler.scheduleEvent (time::seconds (0), // no need to add jitter
- bind (&SyncLogic::sendSyncInterest, this));
-
- m_instanceId = std::string("Instance " + boost::lexical_cast<std::string>(m_instanceCounter++) + " ");
-}
-
-SyncLogic::SyncLogic (const Name& syncPrefix,
- const IdentityCertificate& myCertificate,
- shared_ptr<Validator> validator,
- shared_ptr<Face> face,
- LogicPerBranchCallback onUpdateBranch)
- : m_state (new FullState)
- , m_syncInterestTable (face->getIoService(), time::seconds (m_syncInterestReexpress))
- , m_syncPrefix (syncPrefix)
- , m_myCertificate(myCertificate)
- , m_onUpdateBranch (onUpdateBranch)
- , m_perBranch(true)
- , m_validator(validator)
- , m_face(face)
- , m_scheduler(face->getIoService())
- , m_randomGenerator (static_cast<unsigned int> (std::time (0)))
- , m_rangeUniformRandom (m_randomGenerator, boost::uniform_int<> (200,1000))
- , m_reexpressionJitter (m_randomGenerator, boost::uniform_int<> (100,500))
- , m_recoveryRetransmissionInterval (m_defaultRecoveryRetransmitInterval)
-{
- m_syncRegisteredPrefixId = m_face->setInterestFilter (m_syncPrefix,
- bind(&SyncLogic::onSyncInterest, this, _1, _2),
- bind(&SyncLogic::onSyncRegisterFailed, this, _1, _2));
-
- m_reexpressingInterestId = m_scheduler.scheduleEvent (time::seconds (0), // no need to add jitter
- bind (&SyncLogic::sendSyncInterest, this));
-}
-
-SyncLogic::~SyncLogic ()
-{
- m_face->unsetInterestFilter(m_syncRegisteredPrefixId);
- m_scheduler.cancelEvent (m_reexpressingInterestId);
- m_scheduler.cancelEvent (m_delayedInterestProcessingId);
-}
-
-/**
- * Two types of intersts
- *
- * Normal name: .../<hash>
- * Recovery name: .../recovery/<hash>
- */
-boost::tuple<DigestConstPtr, std::string>
-SyncLogic::convertNameToDigestAndType (const Name &name)
-{
- BOOST_ASSERT (m_syncPrefix.isPrefixOf(name));
-
- int nameLengthDiff = name.size() - m_syncPrefix.size();
- BOOST_ASSERT (nameLengthDiff > 0);
- BOOST_ASSERT (nameLengthDiff < 3);
-
- std::string hash = name.get(-1).toUri();
- std::string interestType;
-
- if(nameLengthDiff == 1)
- interestType = "normal";
- else
- interestType = name.get(-2).toUri();
-
- _LOG_DEBUG_ID (hash << ", " << interestType);
-
- DigestPtr digest = boost::make_shared<Digest> ();
- std::istringstream is (hash);
- is >> *digest;
-
- return make_tuple (digest, interestType);
-}
-
-void
-SyncLogic::onSyncInterest (const Name& prefix, const ndn::Interest& interest)
-{
- Name name = interest.getName();
-
- _LOG_DEBUG_ID("respondSyncInterest: " << name);
-
- try
- {
- _LOG_DEBUG_ID ("<< I " << name);
-
- if(name.get(m_syncPrefix.size()).toUri() == "CHRONOS-INTRO-CERT")
- // it is a certificate, validator will take care of it.
- return;
-
- DigestConstPtr digest;
- std::string type;
- tie (digest, type) = convertNameToDigestAndType (name);
-
- if (type == "normal") // kind of ineffective...
- {
- processSyncInterest (name, digest);
- }
- else if (type == "recovery")
- {
- processSyncRecoveryInterest (name, digest);
- }
- }
- catch (Error::DigestCalculationError &e)
- {
- _LOG_DEBUG_ID ("Something fishy happened...");
- // log error. ignoring it for now, later we should log it
- return ;
- }
-}
-
-void
-SyncLogic::onSyncRegisterFailed(const Name& prefix, const std::string& msg)
-{
- _LOG_DEBUG_ID("Sync prefix registration failed! " << msg);
-}
-
-void
-SyncLogic::onSyncData(const ndn::Interest& interest, Data& data)
-{
- OnDataValidated onValidated = bind(&SyncLogic::onSyncDataValidated, this, _1);
- OnDataValidationFailed onValidationFailed = bind(&SyncLogic::onSyncDataValidationFailed, this, _1);
- m_validator->validate(data, onValidated, onValidationFailed);
-}
-
-void
-SyncLogic::onSyncTimeout(const ndn::Interest& interest)
-{
- // It is OK. Others will handle the time out situation.
-}
-
-void
-SyncLogic::onSyncDataValidationFailed(const shared_ptr<const Data>& data)
-{
- _LOG_DEBUG_ID("Sync data cannot be verified!");
-}
-
-void
-SyncLogic::onSyncDataValidated(const shared_ptr<const Data>& data)
-{
- Name name = data->getName();
- const char* wireData = (const char*)data->getContent().value();
- size_t len = data->getContent().value_size();
-
- try
- {
- _LOG_DEBUG_ID ("<< D " << name);
-
- DigestConstPtr digest;
- std::string type;
- tie (digest, type) = convertNameToDigestAndType (name);
-
- if (type == "normal")
- {
- processSyncData (name, digest, wireData, len);
- }
- else
- {
- // timer is always restarted when we schedule recovery
- m_scheduler.cancelEvent (m_reexpressingRecoveryInterestId);
- processSyncData (name, digest, wireData, len);
- }
- }
- catch (Error::DigestCalculationError &e)
- {
- _LOG_DEBUG_ID ("Something fishy happened...");
- // log error. ignoring it for now, later we should log it
- return;
- }
-}
-
-void
-SyncLogic::processSyncInterest (const Name &name, DigestConstPtr digest, bool timedProcessing/*=false*/)
-{
- _LOG_DEBUG_ID("processSyncInterest");
- DigestConstPtr rootDigest;
- {
- rootDigest = m_state->getDigest();
- }
-
- // Special case when state is not empty and we have received request with zero-root digest
- if (digest->isZero () && !rootDigest->isZero ())
- {
-
- SyncStateMsg ssm;
- {
- ssm << (*m_state);
- }
- sendSyncData (name, digest, ssm);
- return;
- }
-
- if (*rootDigest == *digest)
- {
- _LOG_DEBUG_ID ("processSyncInterest (): Same state. Adding to PIT");
- m_syncInterestTable.insert (digest, name.toUri(), false);
- return;
- }
-
- DiffStateContainer::iterator stateInDiffLog = m_log.find (digest);
-
- if (stateInDiffLog != m_log.end ())
- {
- DiffStateConstPtr stateDiff = (*stateInDiffLog)->diff ();
-
- sendSyncData (name, digest, stateDiff);
- return;
- }
-
- if (!timedProcessing)
- {
- bool exists = m_syncInterestTable.insert (digest, name.toUri(), true);
- if (exists) // somebody else replied, so restart random-game timer
- {
- _LOG_DEBUG_ID ("Unknown digest, but somebody may have already replied, so restart our timer");
- m_scheduler.cancelEvent (m_delayedInterestProcessingId);
- }
-
- uint32_t waitDelay = GET_RANDOM (m_rangeUniformRandom);
- _LOG_DEBUG_ID ("Digest is not in the log. Schedule processing after small delay: " << time::milliseconds (waitDelay));
-
- m_delayedInterestProcessingId = m_scheduler.scheduleEvent (time::milliseconds (waitDelay),
- bind (&SyncLogic::processSyncInterest, this, name, digest, true));
- }
- else
- {
- _LOG_DEBUG_ID (" (timed processing)");
-
- m_recoveryRetransmissionInterval = m_defaultRecoveryRetransmitInterval;
- sendSyncRecoveryInterests (digest);
- }
-}
-
-void
-SyncLogic::processSyncData (const Name &name, DigestConstPtr digest, const char *wireData, size_t len)
-{
- DiffStatePtr diffLog = boost::make_shared<DiffState> ();
- bool ownInterestSatisfied = false;
-
- try
- {
-
- m_syncInterestTable.remove (name.toUri()); // Remove satisfied interest from PIT
-
- ownInterestSatisfied = (name == m_outstandingInterestName);
-
- DiffState diff;
- SyncStateMsg msg;
- if (!msg.ParseFromArray(wireData, len) || !msg.IsInitialized())
- {
- //Throw
- BOOST_THROW_EXCEPTION (Error::SyncStateMsgDecodingFailure () );
- }
- msg >> diff;
-
- std::vector<MissingDataInfo> v;
- BOOST_FOREACH (LeafConstPtr leaf, diff.getLeaves().get<ordered>())
- {
- DiffLeafConstPtr diffLeaf = boost::dynamic_pointer_cast<const DiffLeaf> (leaf);
- BOOST_ASSERT (diffLeaf != 0);
-
- NameInfoConstPtr info = diffLeaf->getInfo();
- if (diffLeaf->getOperation() == UPDATE)
- {
- SeqNo seq = diffLeaf->getSeq();
-
- bool inserted = false;
- bool updated = false;
- SeqNo oldSeq;
- {
- boost::tie (inserted, updated, oldSeq) = m_state->update (info, seq);
- }
-
- if (inserted || updated)
- {
- diffLog->update (info, seq);
- if (!oldSeq.isValid())
- {
- oldSeq = SeqNo(seq.getSession(), 0);
- }
- else
- {
- ++oldSeq;
- }
- // there is no need for application to process update on forwarder node
- if (info->toString() != forwarderPrefix)
- {
- MissingDataInfo mdi = {info->toString(), oldSeq, seq};
- {
- std::ostringstream interestName;
- interestName << mdi.prefix << "/" << mdi.high.getSession() << "/" << mdi.high.getSeq();
- _LOG_DEBUG_ID("+++++++++++++++ " + interestName.str());
- }
- if (m_perBranch)
- {
- std::ostringstream interestName;
- interestName << mdi.prefix << "/" << mdi.high.getSession() << "/" << mdi.high.getSeq();
- m_onUpdateBranch(interestName.str());
- }
- else
- {
- v.push_back(mdi);
- }
- }
- }
- }
- else if (diffLeaf->getOperation() == REMOVE)
- {
- if (m_state->remove (info))
- {
- diffLog->remove (info);
- if (!m_perBranch)
- {
- m_onRemove (info->toString ());
- }
- }
- }
- else
- {
- }
- }
-
- if (!v.empty())
- {
- if (!m_perBranch)
- {
- m_onUpdate(v);
- }
- }
-
- insertToDiffLog (diffLog);
- }
- catch (Error::SyncStateMsgDecodingFailure &e)
- {
- _LOG_DEBUG_ID ("Something really fishy happened during state decoding " <<
- diagnostic_information (e));
- diffLog.reset ();
- // don't do anything
- }
-
- if ((diffLog != 0 && diffLog->getLeaves ().size () > 0) ||
- ownInterestSatisfied)
- {
- _LOG_DEBUG_ID(" +++++++++++++++ state changed!!!");
- // Do it only if everything went fine and state changed
-
- // this is kind of wrong
- // satisfyPendingSyncInterests (diffLog); // if there are interests in PIT, there is a point to satisfy them using new state
-
- // if state has changed, then it is safe to express a new interest
- time::system_clock::Duration after = time::milliseconds(GET_RANDOM (m_reexpressionJitter));
- // cout << "------------ reexpress interest after: " << after << endl;
- EventId eventId = m_scheduler.scheduleEvent (after,
- bind (&SyncLogic::sendSyncInterest, this));
-
- m_scheduler.cancelEvent (m_reexpressingInterestId);
- m_reexpressingInterestId = eventId;
- }
-}
-
-void
-SyncLogic::processSyncRecoveryInterest (const Name &name, DigestConstPtr digest)
-{
- _LOG_DEBUG_ID("processSyncRecoveryInterest");
- DiffStateContainer::iterator stateInDiffLog = m_log.find (digest);
-
- if (stateInDiffLog == m_log.end ())
- {
- _LOG_DEBUG_ID ("Could not find " << *digest << " in digest log");
- return;
- }
-
- SyncStateMsg ssm;
- {
- ssm << (*m_state);
- }
- sendSyncData (name, digest, ssm);
-}
-
-void
-SyncLogic::satisfyPendingSyncInterests (DiffStateConstPtr diffLog)
-{
- DiffStatePtr fullStateLog = boost::make_shared<DiffState> ();
- {
- BOOST_FOREACH (LeafConstPtr leaf, m_state->getLeaves ()/*.get<timed> ()*/)
- {
- fullStateLog->update (leaf->getInfo (), leaf->getSeq ());
- /// @todo Impose limit on how many state info should be send out
- }
- }
-
- try
- {
- uint32_t counter = 0;
- while (m_syncInterestTable.size () > 0)
- {
- Sync::Interest interest = m_syncInterestTable.pop ();
-
- if (!interest.m_unknown)
- {
- _LOG_DEBUG_ID (">> D " << interest.m_name);
- sendSyncData (interest.m_name, interest.m_digest, diffLog);
- }
- else
- {
- _LOG_DEBUG_ID (">> D (unknown)" << interest.m_name);
- sendSyncData (interest.m_name, interest.m_digest, fullStateLog);
- }
- counter ++;
- }
- _LOG_DEBUG_ID ("Satisfied " << counter << " pending interests");
- }
- catch (Error::InterestTableIsEmpty &e)
- {
- // ok. not really an error
- }
-}
-
-void
-SyncLogic::insertToDiffLog (DiffStatePtr diffLog)
-{
- diffLog->setDigest (m_state->getDigest());
- if (m_log.size () > 0)
- {
- m_log.get<sequenced> ().front ()->setNext (diffLog);
- }
- m_log.erase (m_state->getDigest()); // remove diff state with the same digest. next pointers are still valid
- /// @todo Optimization
- m_log.get<sequenced> ().push_front (diffLog);
-}
-
-void
-SyncLogic::addLocalNames (const Name &prefix, uint64_t session, uint64_t seq)
-{
- DiffStatePtr diff;
- {
- //cout << "Add local names" <<endl;
- NameInfoConstPtr info = StdNameInfo::FindOrCreate(prefix.toUri());
-
- _LOG_DEBUG_ID ("addLocalNames (): old state " << *m_state->getDigest ());
-
- SeqNo seqN (session, seq);
- m_state->update(info, seqN);
-
- _LOG_DEBUG_ID ("addLocalNames (): new state " << *m_state->getDigest ());
-
- diff = boost::make_shared<DiffState>();
- diff->update(info, seqN);
- insertToDiffLog (diff);
- }
-
- // _LOG_DEBUG_ID ("PIT size: " << m_syncInterestTable.size ());
- satisfyPendingSyncInterests (diff);
-}
-
-void
-SyncLogic::remove(const Name &prefix)
-{
- DiffStatePtr diff;
- {
- NameInfoConstPtr info = StdNameInfo::FindOrCreate(prefix.toUri());
- m_state->remove(info);
-
- // increment the sequence number for the forwarder node
- NameInfoConstPtr forwarderInfo = StdNameInfo::FindOrCreate(forwarderPrefix);
-
- LeafContainer::iterator item = m_state->getLeaves ().find (forwarderInfo);
- SeqNo seqNo (0);
- if (item != m_state->getLeaves ().end ())
- {
- seqNo = (*item)->getSeq ();
- ++seqNo;
- }
- m_state->update (forwarderInfo, seqNo);
-
- diff = boost::make_shared<DiffState>();
- diff->remove(info);
- diff->update(forwarderInfo, seqNo);
-
- insertToDiffLog (diff);
- }
-
- satisfyPendingSyncInterests (diff);
-}
-
-void
-SyncLogic::sendSyncInterest ()
-{
- _LOG_DEBUG_ID("sendSyncInterest");
-
- {
- m_outstandingInterestName = m_syncPrefix;
- std::ostringstream os;
- os << *m_state->getDigest();
- m_outstandingInterestName.append(os.str());
- _LOG_DEBUG_ID (">> I " << m_outstandingInterestName);
- }
-
- _LOG_DEBUG_ID("sendSyncInterest: " << m_outstandingInterestName);
-
- EventId eventId = m_scheduler.scheduleEvent (time::seconds(m_syncInterestReexpress) + time::milliseconds(GET_RANDOM (m_reexpressionJitter)),
- bind (&SyncLogic::sendSyncInterest, this));
- m_scheduler.cancelEvent (m_reexpressingInterestId);
- m_reexpressingInterestId = eventId;
-
- ndn::Interest interest(m_outstandingInterestName);
- interest.setMustBeFresh(true);
-
- m_face->expressInterest(interest,
- bind(&SyncLogic::onSyncData, this, _1, _2),
- bind(&SyncLogic::onSyncTimeout, this, _1));
-}
-
-void
-SyncLogic::sendSyncRecoveryInterests (DigestConstPtr digest)
-{
- std::ostringstream os;
- os << *digest;
-
- Name interestName = m_syncPrefix;
- interestName.append("recovery").append(os.str());
-
- time::system_clock::Duration nextRetransmission = time::milliseconds (m_recoveryRetransmissionInterval + GET_RANDOM (m_reexpressionJitter));
-
- m_recoveryRetransmissionInterval <<= 1;
-
- m_scheduler.cancelEvent (m_reexpressingRecoveryInterestId);
- if (m_recoveryRetransmissionInterval < 100*1000) // <100 seconds
- m_reexpressingRecoveryInterestId = m_scheduler.scheduleEvent (nextRetransmission,
- bind (&SyncLogic::sendSyncRecoveryInterests, this, digest));
-
- ndn::Interest interest(interestName);
- interest.setMustBeFresh(true);
-
- m_face->expressInterest(interest,
- bind(&SyncLogic::onSyncData, this, _1, _2),
- bind(&SyncLogic::onSyncTimeout, this, _1));
-}
-
-
-void
-SyncLogic::sendSyncData (const Name &name, DigestConstPtr digest, StateConstPtr state)
-{
- SyncStateMsg msg;
- msg << (*state);
- sendSyncData(name, digest, msg);
-}
-
-// pass in state msg instead of state, so that there is no need to lock the state until
-// this function returns
-void
-SyncLogic::sendSyncData (const Name &name, DigestConstPtr digest, SyncStateMsg &ssm)
-{
- _LOG_DEBUG_ID (">> D " << name);
- int size = ssm.ByteSize();
- char *wireData = new char[size];
- ssm.SerializeToArray(wireData, size);
-
- Data syncData(name);
- syncData.setContent(reinterpret_cast<const uint8_t*>(wireData), size);
- syncData.setFreshnessPeriod(time::milliseconds(m_syncResponseFreshness));
-
- m_keyChain.sign(syncData, m_myCertificate.getName());
-
- m_face->put(syncData);
-
- delete []wireData;
-
- // checking if our own interest got satisfied
- bool satisfiedOwnInterest = false;
- {
- satisfiedOwnInterest = (m_outstandingInterestName == name);
- }
-
- if (satisfiedOwnInterest)
- {
- _LOG_DEBUG_ID ("Satisfied our own Interest. Re-expressing (hopefully with a new digest)");
-
- time::system_clock::Duration after = time::milliseconds(GET_RANDOM (m_reexpressionJitter));
- // cout << "------------ reexpress interest after: " << after << endl;
- EventId eventId = m_scheduler.scheduleEvent (after,
- bind (&SyncLogic::sendSyncInterest, this));
- m_scheduler.cancelEvent (m_reexpressingInterestId);
- m_reexpressingInterestId = eventId;
- }
-}
-
-std::string
-SyncLogic::getRootDigest()
-{
- std::ostringstream os;
- os << *m_state->getDigest();
- return os.str();
-}
-
-size_t
-SyncLogic::getNumberOfBranches () const
-{
- return m_state->getLeaves ().size ();
-}
-
-void
-SyncLogic::printState () const
-{
- BOOST_FOREACH (const boost::shared_ptr<Sync::Leaf> leaf, m_state->getLeaves ())
- {
- std::cout << *leaf << std::endl;
- }
-}
-
-std::map<std::string, bool>
-SyncLogic::getBranchPrefixes() const
-{
- std::map<std::string, bool> m;
-
- BOOST_FOREACH (const boost::shared_ptr<Sync::Leaf> leaf, m_state->getLeaves ())
- {
- std::string prefix = leaf->getInfo()->toString();
- // do not return forwarder prefix
- if (prefix != forwarderPrefix)
- {
- m.insert(std::pair<std::string, bool>(prefix, false));
- }
- }
-
- return m;
-}
-
-}
diff --git a/src/sync-logic.h b/src/sync-logic.h
deleted file mode 100644
index 181979b..0000000
--- a/src/sync-logic.h
+++ /dev/null
@@ -1,214 +0,0 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2012-2014 University of California, Los Angeles
- *
- * This file is part of ChronoSync, synchronization library for distributed realtime
- * applications for NDN.
- *
- * ChronoSync 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.
- *
- * ChronoSync 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
- * ChronoSync, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- *
- * @author Zhenkai Zhu <http://irl.cs.ucla.edu/~zhenkai/>
- * @author Chaoyi Bian <bcy@pku.edu.cn>
- * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
- * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/web/index.html>
- */
-
-#ifndef SYNC_LOGIC_H
-#define SYNC_LOGIC_H
-
-#include "boost-header.h"
-#include <memory>
-#include <map>
-
-#include <ndn-cxx/face.hpp>
-#include <ndn-cxx/security/validator.hpp>
-#include <ndn-cxx/security/key-chain.hpp>
-#include <ndn-cxx/util/scheduler.hpp>
-
-#include "sync-interest-table.h"
-#include "sync-diff-state.h"
-#include "sync-full-state.h"
-#include "sync-std-name-info.h"
-
-#include "sync-diff-state-container.h"
-
-#ifdef _DEBUG
-#ifdef HAVE_LOG4CXX
-#include <log4cxx/logger.h>
-#endif
-#endif
-
-namespace Sync {
-
-struct MissingDataInfo {
- std::string prefix;
- SeqNo low;
- SeqNo high;
-};
-
-/**
- * \ingroup sync
- * @brief A wrapper for SyncApp, which handles ccnx related things (process
- * interests and data)
- */
-
-class SyncLogic
-{
-public:
- //typedef boost::function< void ( const std::string &/*prefix*/, const SeqNo &/*newSeq*/, const SeqNo &/*oldSeq*/ ) > LogicUpdateCallback;
- typedef boost::function< void (const std::vector<MissingDataInfo> & ) > LogicUpdateCallback;
- typedef boost::function< void (const std::string &/*prefix*/ ) > LogicRemoveCallback;
- typedef boost::function< void (const std::string &)> LogicPerBranchCallback;
-
- SyncLogic (const ndn::Name& syncPrefix,
- const ndn::IdentityCertificate& myCertificate,
- ndn::shared_ptr<ndn::Validator> validator,
- ndn::shared_ptr<ndn::Face> face,
- LogicUpdateCallback onUpdate,
- LogicRemoveCallback onRemove);
-
- SyncLogic (const ndn::Name& syncPrefix,
- const ndn::IdentityCertificate& myCertificate,
- ndn::shared_ptr<ndn::Validator> validator,
- ndn::shared_ptr<ndn::Face> face,
- LogicPerBranchCallback onUpdateBranch);
-
- ~SyncLogic ();
-
- /**
- * a wrapper for the same func in SyncApp
- */
- void addLocalNames (const ndn::Name &prefix, uint64_t session, uint64_t seq);
-
- /**
- * @brief remove a participant's subtree from the sync tree
- * @param prefix the name prefix for the participant
- */
- void remove (const ndn::Name &prefix);
-
- std::string
- getRootDigest();
-
-#ifdef _DEBUG
- ndn::Scheduler &
- getScheduler () { return m_scheduler; }
-#endif
-
- void
- printState () const;
-
- std::map<std::string, bool>
- getBranchPrefixes() const;
-
-private:
- void
- delayedChecksLoop ();
-
- void
- onSyncInterest (const ndn::Name& prefix, const ndn::Interest& interest);
-
- void
- onSyncRegisterFailed(const ndn::Name& prefix, const std::string& msg);
-
- void
- onSyncData(const ndn::Interest& interest, ndn::Data& data);
-
- void
- onSyncTimeout(const ndn::Interest& interest);
-
- void
- onSyncDataValidationFailed(const ndn::shared_ptr<const ndn::Data>& data);
-
- void
- onSyncDataValidated(const ndn::shared_ptr<const ndn::Data>& data);
-
- void
- processSyncInterest (const ndn::Name &name,
- DigestConstPtr digest, bool timedProcessing=false);
-
- void
- processSyncData (const ndn::Name &name,
- DigestConstPtr digest, const char *wireData, size_t len);
-
- void
- processSyncRecoveryInterest (const ndn::Name &name,
- DigestConstPtr digest);
-
- void
- insertToDiffLog (DiffStatePtr diff);
-
- void
- satisfyPendingSyncInterests (DiffStateConstPtr diff);
-
- boost::tuple<DigestConstPtr, std::string>
- convertNameToDigestAndType (const ndn::Name &name);
-
- void
- sendSyncInterest ();
-
- void
- sendSyncRecoveryInterests (DigestConstPtr digest);
-
- void
- sendSyncData (const ndn::Name &name,
- DigestConstPtr digest, StateConstPtr state);
-
- void
- sendSyncData (const ndn::Name &name,
- DigestConstPtr digest, SyncStateMsg &msg);
-
- size_t
- getNumberOfBranches () const;
-
-private:
- FullStatePtr m_state;
- DiffStateContainer m_log;
-
- ndn::Name m_outstandingInterestName;
- SyncInterestTable m_syncInterestTable;
-
- ndn::Name m_syncPrefix;
- ndn::IdentityCertificate m_myCertificate;
- LogicUpdateCallback m_onUpdate;
- LogicRemoveCallback m_onRemove;
- LogicPerBranchCallback m_onUpdateBranch;
- bool m_perBranch;
- ndn::shared_ptr<ndn::Validator> m_validator;
- ndn::KeyChain m_keyChain;
- ndn::shared_ptr<ndn::Face> m_face;
- const ndn::RegisteredPrefixId* m_syncRegisteredPrefixId;
-
- ndn::Scheduler m_scheduler;
-
- boost::mt19937 m_randomGenerator;
- boost::variate_generator<boost::mt19937&, boost::uniform_int<> > m_rangeUniformRandom;
- boost::variate_generator<boost::mt19937&, boost::uniform_int<> > m_reexpressionJitter;
-
- static const int m_unknownDigestStoreTime = 10; // seconds
- static const int m_syncResponseFreshness; // MUST BE dividable by 1000!!!
- static const int m_syncInterestReexpress; // seconds
-
- static const int m_defaultRecoveryRetransmitInterval = 200; // milliseconds
- uint32_t m_recoveryRetransmissionInterval; // milliseconds
-
- ndn::EventId m_delayedInterestProcessingId;
- ndn::EventId m_reexpressingInterestId;
- ndn::EventId m_reexpressingRecoveryInterestId;
-
- std::string m_instanceId;
- static int m_instanceCounter;
-};
-
-
-} // Sync
-
-#endif // SYNC_APP_WRAPPER_H
diff --git a/tests/unit-tests/test-data-fetch-and-publish.cpp.outdated b/tests/integrated-tests/test-data-fetch-and-publish.cpp.outdated
similarity index 100%
rename from tests/unit-tests/test-data-fetch-and-publish.cpp.outdated
rename to tests/integrated-tests/test-data-fetch-and-publish.cpp.outdated
diff --git a/tests/integrated-tests/test-logic.cpp b/tests/integrated-tests/test-logic.cpp
new file mode 100644
index 0000000..088b8fb
--- /dev/null
+++ b/tests/integrated-tests/test-logic.cpp
@@ -0,0 +1,307 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012-2014 University of California, Los Angeles
+ *
+ * This file is part of ChronoSync, synchronization library for distributed realtime
+ * applications for NDN.
+ *
+ * ChronoSync 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.
+ *
+ * ChronoSync 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
+ * ChronoSync, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "logic.hpp"
+
+#include "boost-test.hpp"
+
+namespace chronosync {
+namespace test {
+
+using std::vector;
+
+class Handler
+{
+public:
+ Handler(ndn::Face& face,
+ const Name& syncPrefix,
+ const Name& userPrefix)
+ : logic(face,
+ syncPrefix,
+ userPrefix,
+ bind(&Handler::onUpdate, this, _1))
+ {
+ }
+
+ void
+ onUpdate(const vector<MissingDataInfo>& v)
+ {
+ for (size_t i = 0; i < v.size(); i++) {
+ update(v[i].session, v[i].high, v[i].low);
+ }
+ }
+
+ void
+ update(const Name& p, const SeqNo& high, const SeqNo& low)
+ {
+ map[p] = high;
+ }
+
+ void
+ updateSeqNo(const SeqNo& seqNo)
+ {
+ logic.updateSeqNo(seqNo);
+ }
+
+ void
+ check(const Name& sessionName, const SeqNo& seqNo)
+ {
+ BOOST_CHECK_EQUAL(map[sessionName], seqNo);
+ }
+
+ Logic logic;
+ std::map<Name, SeqNo> map;
+};
+
+class LogicFixture
+{
+public:
+ LogicFixture()
+ : syncPrefix("/ndn/broadcast/sync")
+ , scheduler(io)
+ {
+ syncPrefix.appendVersion();
+ userPrefix[0] = Name("/user0");
+ userPrefix[1] = Name("/user1");
+ userPrefix[2] = Name("/user2");
+
+ faces[0] = make_shared<ndn::Face>(ref(io));
+ faces[1] = make_shared<ndn::Face>(ref(io));
+ faces[2] = make_shared<ndn::Face>(ref(io));
+ }
+
+ void
+ createHandler(size_t idx)
+ {
+ handler[idx] = make_shared<Handler>(ref(*faces[idx]), syncPrefix, userPrefix[idx]);
+ }
+
+ void
+ updateSeqNo(size_t idx, const SeqNo& seqNo)
+ {
+ handler[idx]->updateSeqNo(seqNo);
+ }
+
+ void
+ checkSeqNo(size_t sIdx, size_t dIdx, const SeqNo& seqNo)
+ {
+ handler[sIdx]->check(handler[dIdx]->logic.getSessionName(), seqNo);
+ }
+
+ void
+ terminate()
+ {
+ io.stop();
+ }
+
+ Name syncPrefix;
+ Name userPrefix[3];
+
+ boost::asio::io_service io;
+ shared_ptr<ndn::Face> faces[3];
+ ndn::Scheduler scheduler;
+ shared_ptr<Handler> handler[3];
+};
+
+BOOST_FIXTURE_TEST_SUITE(LogicTests, LogicFixture)
+
+void
+onUpdate(const vector<MissingDataInfo>& v)
+{
+}
+
+BOOST_AUTO_TEST_CASE(Constructor)
+{
+ Name syncPrefix("/ndn/broadcast/sync");
+ Name userPrefix("/user");
+ ndn::Face face;
+ BOOST_REQUIRE_NO_THROW(Logic(face, syncPrefix, userPrefix,
+ bind(onUpdate, _1)));
+}
+
+BOOST_AUTO_TEST_CASE(TwoBasic)
+{
+ scheduler.scheduleEvent(ndn::time::milliseconds(100),
+ bind(&LogicFixture::createHandler, this, 0));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(200),
+ bind(&LogicFixture::createHandler, this, 1));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(300),
+ bind(&LogicFixture::updateSeqNo, this, 0, 1));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(1000),
+ bind(&LogicFixture::checkSeqNo, this, 1, 0, 1));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(1100),
+ bind(&LogicFixture::updateSeqNo, this, 0, 2));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(1800),
+ bind(&LogicFixture::checkSeqNo, this, 1, 0, 2));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(1900),
+ bind(&LogicFixture::updateSeqNo, this, 1, 2));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(2600),
+ bind(&LogicFixture::checkSeqNo, this, 0, 1, 2));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(2800),
+ bind(&LogicFixture::terminate, this));
+
+ io.run();
+}
+
+BOOST_AUTO_TEST_CASE(ThreeBasic)
+{
+ scheduler.scheduleEvent(ndn::time::milliseconds(100),
+ bind(&LogicFixture::createHandler, this, 0));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(200),
+ bind(&LogicFixture::createHandler, this, 1));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(300),
+ bind(&LogicFixture::createHandler, this, 2));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(500),
+ bind(&LogicFixture::updateSeqNo, this, 0, 1));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(1400),
+ bind(&LogicFixture::checkSeqNo, this, 1, 0, 1));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(1450),
+ bind(&LogicFixture::checkSeqNo, this, 2, 0, 1));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(1500),
+ bind(&LogicFixture::updateSeqNo, this, 1, 2));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(2400),
+ bind(&LogicFixture::checkSeqNo, this, 0, 1, 2));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(2450),
+ bind(&LogicFixture::checkSeqNo, this, 2, 1, 2));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(2500),
+ bind(&LogicFixture::updateSeqNo, this, 2, 4));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(4400),
+ bind(&LogicFixture::checkSeqNo, this, 0, 2, 4));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(4450),
+ bind(&LogicFixture::checkSeqNo, this, 1, 2, 4));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(4500),
+ bind(&LogicFixture::terminate, this));
+
+ io.run();
+}
+
+BOOST_AUTO_TEST_CASE(ResetRecover)
+{
+ scheduler.scheduleEvent(ndn::time::milliseconds(100),
+ bind(&LogicFixture::createHandler, this, 0));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(200),
+ bind(&LogicFixture::createHandler, this, 1));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(500),
+ bind(&LogicFixture::updateSeqNo, this, 0, 1));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(1400),
+ bind(&LogicFixture::checkSeqNo, this, 1, 0, 1));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(1500),
+ bind(&LogicFixture::updateSeqNo, this, 1, 2));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(2400),
+ bind(&LogicFixture::checkSeqNo, this, 0, 1, 2));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(2500),
+ bind(&LogicFixture::createHandler, this, 2));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(3000),
+ bind(&LogicFixture::checkSeqNo, this, 1, 0, 1));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(3050),
+ bind(&LogicFixture::checkSeqNo, this, 0, 1, 2));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(3100),
+ bind(&LogicFixture::updateSeqNo, this, 2, 4));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(4000),
+ bind(&LogicFixture::checkSeqNo, this, 1, 2, 4));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(4050),
+ bind(&LogicFixture::checkSeqNo, this, 0, 2, 4));
+
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(4500),
+ bind(&LogicFixture::terminate, this));
+
+ io.run();
+}
+
+BOOST_AUTO_TEST_CASE(RecoverConflict)
+{
+ scheduler.scheduleEvent(ndn::time::milliseconds(0),
+ bind(&LogicFixture::createHandler, this, 0));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(50),
+ bind(&LogicFixture::createHandler, this, 1));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(100),
+ bind(&LogicFixture::createHandler, this, 2));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(500),
+ bind(&LogicFixture::updateSeqNo, this, 0, 1));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(1400),
+ bind(&LogicFixture::checkSeqNo, this, 1, 0, 1));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(1400),
+ bind(&LogicFixture::checkSeqNo, this, 2, 0, 1));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(1500),
+ bind(&LogicFixture::updateSeqNo, this, 1, 2));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(1500),
+ bind(&LogicFixture::updateSeqNo, this, 2, 4));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(2400),
+ bind(&LogicFixture::checkSeqNo, this, 0, 1, 2));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(2450),
+ bind(&LogicFixture::checkSeqNo, this, 0, 2, 4));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(2500),
+ bind(&LogicFixture::checkSeqNo, this, 1, 2, 4));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(2550),
+ bind(&LogicFixture::checkSeqNo, this, 2, 1, 2));
+
+ scheduler.scheduleEvent(ndn::time::milliseconds(4500),
+ bind(&LogicFixture::terminate, this));
+
+ io.run();
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace test
+} // namespace chronosync
diff --git a/tests/unit-tests/test-socket.cpp.outdated b/tests/integrated-tests/test-socket.cpp.outdated
similarity index 100%
rename from tests/unit-tests/test-socket.cpp.outdated
rename to tests/integrated-tests/test-socket.cpp.outdated
diff --git a/tests/unit-tests/test-scheduler.cc.tmp b/tests/unit-tests/test-scheduler.cc.tmp
deleted file mode 100644
index 2a53a22..0000000
--- a/tests/unit-tests/test-scheduler.cc.tmp
+++ /dev/null
@@ -1,175 +0,0 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2012-2014 University of California, Los Angeles
- *
- * This file is part of ChronoSync, synchronization library for distributed realtime
- * applications for NDN.
- *
- * ChronoSync 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.
- *
- * ChronoSync 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
- * ChronoSync, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <boost/test/unit_test.hpp>
-#include <boost/test/output_test_stream.hpp>
-#include <map>
-using boost::test_tools::output_test_stream;
-
-#include <boost/make_shared.hpp>
-#include "sync-scheduler.h"
-#include "sync-logic.h"
-
-using namespace Sync;
-using namespace std;
-using namespace boost;
-
-
-
-// void funcUpdate (const std::string &, const SeqNo &newSeq, const SeqNo &oldSeq)
-// {
-// cout << "funcUpdate\n";
-// }
-
-// void funcRemove (const std::string &)
-// {
-// cout << "funcRemove\n";
-// }
-
-enum SCHEDULE_LABELS
- {
- TEST_LABEL,
- ANOTHER_LABEL
- };
-
-struct SchedulerFixture
-{
- SchedulerFixture ()
- : counter (0)
- {}
-
- int counter;
-
- Scheduler *scheduler;
-
- void everySecond ()
- {
- // cout << "." << flush;
- counter ++;
-
- if (counter < 9)
- scheduler->schedule (boost::posix_time::milliseconds (100),
- boost::bind (&SchedulerFixture::everySecond, this),
- TEST_LABEL);
- }
-
- void setCounterFive ()
- {
- counter = 5;
- }
-
- void setCounterThree ()
- {
- counter = 3;
- }
-};
-
-
-#ifdef _DEBUG
-
-BOOST_FIXTURE_TEST_SUITE (SchedulerTestSuite, SchedulerFixture)
-
-BOOST_AUTO_TEST_CASE (BasicTest)
-{
- BOOST_CHECK_NO_THROW (scheduler = new Scheduler ());
-
- scheduler->schedule (posix_time::milliseconds (100),
- bind (&SchedulerFixture::everySecond, this),
- TEST_LABEL);
-
- sleep (1);
- // cout << counter << endl;
- BOOST_CHECK_EQUAL (counter, 9); // generally, should be 9
-
- scheduler->schedule (posix_time::seconds (2),
- bind (&SchedulerFixture::setCounterFive, this),
- TEST_LABEL);
-
- this_thread::sleep (posix_time::milliseconds (400)); // just in case
-
- scheduler->schedule (posix_time::milliseconds (600),
- bind (&SchedulerFixture::setCounterThree, this),
- TEST_LABEL);
-
- this_thread::sleep (posix_time::milliseconds (500));
- BOOST_CHECK_EQUAL (counter, 9); // still 9
-
- this_thread::sleep (posix_time::milliseconds (200));
- BOOST_CHECK_EQUAL (counter, 3);
-
- this_thread::sleep (posix_time::milliseconds (1000));
- BOOST_CHECK_EQUAL (counter, 5);
-
- scheduler->schedule (posix_time::milliseconds (100),
- bind (&SchedulerFixture::setCounterThree, this),
- ANOTHER_LABEL);
- this_thread::sleep (posix_time::milliseconds (50));
- scheduler->cancel (ANOTHER_LABEL);
- this_thread::sleep (posix_time::milliseconds (150));
- BOOST_CHECK_EQUAL (counter, 5);
-
- BOOST_CHECK_NO_THROW (delete scheduler);
-}
-
-BOOST_AUTO_TEST_SUITE_END ()
-
-
-void funcUpdate( const std::string &/*prefix*/, const SeqNo &/*newSeq*/, const SeqNo &/*oldSeq*/ )
-{
-}
-
-void funcPass( const std::vector<MissingDataInfo> &v)
-{
-}
-
-void funcRemove( const std::string &/*prefix*/ )
-{
-}
-
-BOOST_AUTO_TEST_CASE (SyncLogicSchedulerTest)
-{
- SyncLogic *logic = 0;
- BOOST_CHECK_NO_THROW (logic = new SyncLogic ("/prefix", funcPass, funcRemove));
- this_thread::sleep (posix_time::milliseconds (100));
-
- Scheduler &scheduler = logic->getScheduler ();
- BOOST_CHECK_EQUAL (scheduler.getEventsSize (), 1);
-
- BOOST_CHECK_NO_THROW (logic->respondSyncInterest ("/prefix/e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e"));
- BOOST_CHECK_EQUAL (scheduler.getEventsSize (), 2);
-
- this_thread::sleep (posix_time::milliseconds (100)); // max waiting time
- BOOST_CHECK_EQUAL (scheduler.getEventsSize (), 1);
-
- BOOST_CHECK_NO_THROW (logic->respondSyncInterest ("/prefix/e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e"));
- BOOST_CHECK_NO_THROW (logic->respondSyncInterest ("/prefix/e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e"));
- BOOST_CHECK_NO_THROW (logic->respondSyncInterest ("/prefix/e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e"));
- BOOST_CHECK_NO_THROW (logic->respondSyncInterest ("/prefix/e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e"));
- BOOST_CHECK_EQUAL (scheduler.getEventsSize (), 5);
-
- this_thread::sleep (posix_time::milliseconds (19)); // min waiting time is 20
- BOOST_CHECK_EQUAL (scheduler.getEventsSize (), 5);
-
- this_thread::sleep (posix_time::milliseconds (100)); // max waiting time
- BOOST_CHECK_EQUAL (scheduler.getEventsSize (), 1);
-
- BOOST_CHECK_NO_THROW (delete logic);
-}
-
-#endif
diff --git a/tests/unit-tests/test-sync-logic.cpp.outdated b/tests/unit-tests/test-sync-logic.cpp.outdated
deleted file mode 100644
index e916ad5..0000000
--- a/tests/unit-tests/test-sync-logic.cpp.outdated
+++ /dev/null
@@ -1,181 +0,0 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2012-2014 University of California, Los Angeles
- *
- * This file is part of ChronoSync, synchronization library for distributed realtime
- * applications for NDN.
- *
- * ChronoSync 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.
- *
- * ChronoSync 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
- * ChronoSync, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <boost/test/unit_test.hpp>
-#include <boost/test/output_test_stream.hpp>
-#include <map>
-using boost::test_tools::output_test_stream;
-
-#include <boost/make_shared.hpp>
-
-#include <ndn-cxx/security/validator-null.hpp>
-#include "sync-logic.h"
-#include "sync-seq-no.h"
-
-using namespace std;
-using namespace boost;
-using namespace Sync;
-
-struct Handler
-{
- string instance;
-
- Handler (const string &_instance)
- : instance (_instance)
- {
- }
-
- void wrapper (const vector<MissingDataInfo> &v) {
- int n = v.size();
- for (int i = 0; i < n; i++) {
- onUpdate (v[i].prefix, v[i].high, v[i].low);
- }
- }
-
- void onUpdate (const string &p/*prefix*/, const SeqNo &seq/*newSeq*/, const SeqNo &oldSeq/*oldSeq*/)
- {
- m_map[p] = seq.getSeq ();
-
- // cout << instance << "\t";
- // if (!oldSeq.isValid ())
- // cout << "Inserted: " << p << " (" << seq << ")" << endl;
- // else
- // cout << "Updated: " << p << " ( " << oldSeq << ".." << seq << ")" << endl;
- }
-
- void onRemove (const string &p/*prefix*/)
- {
- // cout << instance << "\tRemoved: " << p << endl;
- m_map.erase (p);
- }
-
- map<string, uint32_t> m_map;
-};
-
-class TestCore
-{
-public:
- TestCore(ndn::shared_ptr<boost::asio::io_service> ioService)
- : m_ioService(ioService)
- {
- m_l[0] = 0;
- m_l[1] = 0;
-
- m_validator = ndn::make_shared<ndn::ValidatorNull>();
- }
-
- ~TestCore()
- {
- if(m_l[0] != 0)
- delete m_l[0];
-
- if(m_l[1] != 0)
- delete m_l[1];
- }
-
- void
- finish(ndn::shared_ptr<boost::asio::io_service> ioService)
- {
- ioService->stop();
- }
-
- void
- createSyncLogic(int index,
- ndn::shared_ptr<Handler> h)
- {
- ndn::Name identity("/tmp-" + boost::lexical_cast<std::string>(ndn::time::toUnixTimestamp(ndn::time::system_clock::now()).count()));
- ndn::shared_ptr<ndn::IdentityCertificate> cert = m_keyChain.getCertificate(m_keyChain.createIdentity(identity));
- m_faces[index] = ndn::make_shared<ndn::Face>(ndn::ref(*m_ioService));
- m_l[index] = new SyncLogic(ndn::Name("/bcast"),
- *cert,
- m_validator, m_faces[index],
- bind (&Handler::wrapper, &*h, _1),
- bind (&Handler::onRemove, &*h, _1));
- }
-
- void
- getOldDigestForOne()
- {
- m_oldDigest = m_l[0]->getRootDigest();
- }
-
- void
- getNewDigestForOne()
- {
- m_newDigest = m_l[0]->getRootDigest();
- }
-
- void
- addLocalNamesForOne(ndn::Name name, uint64_t session, uint64_t seq)
- {
- m_l[0]->addLocalNames(name, session, seq);
- }
-
- void
- removeForOne(ndn::Name name)
- {
- m_l[0]->remove(name);
- }
-
- void
- checkDigest()
- {
- BOOST_CHECK(m_oldDigest != m_newDigest);
- }
-
-
-public:
- ndn::KeyChain m_keyChain;
- ndn::shared_ptr<boost::asio::io_service> m_ioService;
- SyncLogic* m_l[2];
- ndn::shared_ptr<ndn::Face> m_faces[2];
- ndn::shared_ptr<ndn::ValidatorNull> m_validator;
- string m_oldDigest;
- string m_newDigest;
-};
-
-void
-checkMapSize(ndn::shared_ptr<Handler> h, int size)
-{ BOOST_CHECK_EQUAL (h->m_map.size (), size); }
-
-
-BOOST_AUTO_TEST_CASE (SyncLogicTest)
-{
- ndn::shared_ptr<boost::asio::io_service> ioService = ndn::make_shared<boost::asio::io_service>();
- ndn::Scheduler scheduler(*ioService);
- TestCore testCore(ioService);
-
- ndn::shared_ptr<Handler> h1 = ndn::make_shared<Handler>("1");
- ndn::shared_ptr<Handler> h2 = ndn::make_shared<Handler>("2");
-
- scheduler.scheduleEvent(ndn::time::milliseconds(0), ndn::bind(&TestCore::createSyncLogic, &testCore, 0, h1));
- scheduler.scheduleEvent(ndn::time::milliseconds(100), ndn::bind(&TestCore::getOldDigestForOne, &testCore));
- scheduler.scheduleEvent(ndn::time::milliseconds(200), ndn::bind(&TestCore::addLocalNamesForOne, &testCore, "/one", 1, 2));
- scheduler.scheduleEvent(ndn::time::milliseconds(300), ndn::bind(&checkMapSize, h1, 0));
- scheduler.scheduleEvent(ndn::time::milliseconds(400), ndn::bind(&TestCore::createSyncLogic, &testCore, 1, h2));
- scheduler.scheduleEvent(ndn::time::milliseconds(500), ndn::bind(&checkMapSize, h1, 0));
- scheduler.scheduleEvent(ndn::time::milliseconds(600), ndn::bind(&checkMapSize, h2, 1));
- scheduler.scheduleEvent(ndn::time::milliseconds(700), ndn::bind(&TestCore::removeForOne, &testCore, "/one"));
- scheduler.scheduleEvent(ndn::time::milliseconds(800), ndn::bind(&TestCore::getNewDigestForOne, &testCore));
- scheduler.scheduleEvent(ndn::time::milliseconds(900), ndn::bind(&TestCore::checkDigest, &testCore));
- scheduler.scheduleEvent(ndn::time::milliseconds(1000), ndn::bind(&TestCore::finish, &testCore, ioService));
-
- ioService->run();
-
-}
diff --git a/tests/wscript b/tests/wscript
index d1a61ba..384dbba 100644
--- a/tests/wscript
+++ b/tests/wscript
@@ -4,9 +4,9 @@
top = '..'
def build(bld):
- unit_test_main = bld(
- target='unit-tests-main',
- name='unit-tests-main',
+ test_main = bld(
+ target='tests-main',
+ name='tests-main',
features='cxx',
source=bld.path.ant_glob(['main.cpp']),
use='ChronoSync',
@@ -16,7 +16,16 @@
target="../unit-tests",
source=bld.path.ant_glob(['unit-tests/**/*.cpp']),
features=['cxx', 'cxxprogram'],
- use='ChronoSync, unit-tests-main',
+ use='ChronoSync tests-main LOG4CXX',
+ includes=['.'],
+ install_path=None,
+ )
+
+ integrated_test = bld.program(
+ target="../integrated-tests",
+ source=bld.path.ant_glob(['integrated-tests/**/*.cpp']),
+ features=['cxx', 'cxxprogram'],
+ use='ChronoSync tests-main',
includes=['.'],
install_path=None,
)
diff --git a/wscript b/wscript
index 0f0ea36..025e481 100644
--- a/wscript
+++ b/wscript
@@ -48,7 +48,7 @@
# vnum = "1.0.0",
features=['cxx', 'cxxshlib'],
source = bld.path.ant_glob(['src/**/*.cpp', 'src/**/*.proto']),
- use = 'BOOST NDN_CXX',
+ use = 'BOOST NDN_CXX LOG4CXX',
includes = ['src', '.'],
export_includes=['src', '.'],
)
@@ -57,23 +57,18 @@
if bld.env["_TESTS"]:
bld.recurse('tests')
- if bld.get_define("HAVE_LOG4CXX"):
- libsync.use += ' LOG4CXX'
- if bld.env["_TESTS"]:
- unittests.use += ' LOG4CXX'
-
bld.install_files(
dest = "%s/ChronoSync" % bld.env['INCLUDEDIR'],
- files = bld.path.ant_glob(['src/**/*.h']),
+ files = bld.path.ant_glob(['src/**/*.hpp', 'src/**/*.h', 'common.hpp']),
cwd = bld.path.find_dir("src"),
- relative_trick = True,
+ relative_trick = False,
)
bld.install_files(
dest = "%s/ChronoSync" % bld.env['INCLUDEDIR'],
- files = bld.path.get_bld().ant_glob(['src/**/*.h']),
+ files = bld.path.get_bld().ant_glob(['src/**/*.hpp', 'src/**/*.h', 'common.hpp', 'config.hpp']),
cwd = bld.path.get_bld().find_dir("src"),
- relative_trick = True,
+ relative_trick = False,
)
pc = bld(