api: Major API change. OnInterest/OnData callbacks now use just references, not shared pointers
If shared pointer is necessary, it can be obtained using
.shared_from_this() on Interest or Data object.
This commit also corrects all internal uses of expressInterest/setIntersetFilter.
Change-Id: I20207a5789fd189902f2c6e3827260b6b27a2514
diff --git a/src/face.cpp b/src/face.cpp
index 9385358..7e62fe4 100644
--- a/src/face.cpp
+++ b/src/face.cpp
@@ -5,34 +5,342 @@
* See COPYING for copyright and distribution information.
*/
+#include "common.hpp"
+
#include "face.hpp"
-using namespace std;
+#include "security/signature-sha256-with-rsa.hpp"
+
+#include "util/time.hpp"
+#include "util/random.hpp"
+
+#include "management/ndnd-controller.hpp"
+#include "management/nfd-controller.hpp"
namespace ndn {
-const PendingInterestId*
-Face::expressInterest
- (const Name& name, const Interest *interestTemplate, const OnData& onData, const OnTimeout& onTimeout)
+Face::Face(bool nfdMode/* = false*/)
{
- if (interestTemplate)
- return node_.expressInterest(Interest
- (name,
- interestTemplate->getMinSuffixComponents(), interestTemplate->getMaxSuffixComponents(),
- interestTemplate->getExclude(),
- interestTemplate->getChildSelector(),
- interestTemplate->getMustBeFresh(),
- interestTemplate->getScope(),
- interestTemplate->getInterestLifetime()),
- onData, onTimeout);
+ construct(shared_ptr<Transport>(new UnixTransport()),
+ make_shared<boost::asio::io_service>(), nfdMode);
+}
+
+Face::Face(const shared_ptr<boost::asio::io_service> &ioService, bool nfdMode/* = false*/)
+{
+ construct(shared_ptr<Transport>(new UnixTransport()),
+ ioService, nfdMode);
+}
+
+Face::Face(const std::string &host, const std::string &port/* = "6363"*/, bool nfdMode/* = false*/)
+{
+ construct(shared_ptr<Transport>(new TcpTransport(host, port)),
+ make_shared<boost::asio::io_service>(), nfdMode);
+}
+
+Face::Face(const shared_ptr<Transport>& transport, bool nfdMode/* = false*/)
+{
+ construct(transport,
+ make_shared<boost::asio::io_service>(), nfdMode);
+}
+
+Face::Face(const shared_ptr<Transport>& transport,
+ const shared_ptr<boost::asio::io_service> &ioService,
+ bool nfdMode/* = false*/)
+{
+ construct(transport, ioService, nfdMode);
+}
+
+void
+Face::construct(const shared_ptr<Transport>& transport,
+ const shared_ptr<boost::asio::io_service> &ioService,
+ bool nfdMode)
+{
+ pitTimeoutCheckTimerActive_ = false;
+ transport_ = transport;
+ ioService_ = ioService;
+
+ pitTimeoutCheckTimer_ = make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
+ processEventsTimeoutTimer_ = make_shared<boost::asio::deadline_timer>(boost::ref(*ioService_));
+
+ if (nfdMode)
+ m_fwController = make_shared<nfd::Controller>(boost::ref(*this));
else
- return node_.expressInterest(Interest(name, 4000.0), onData, onTimeout);
+ m_fwController = make_shared<ndnd::Controller>(boost::ref(*this));
+}
+
+
+const PendingInterestId*
+Face::expressInterest(const Interest& interest, const OnData& onData, const OnTimeout& onTimeout)
+{
+ if (!transport_->isConnected())
+ transport_->connect(*ioService_,
+ bind(&Face::onReceiveElement, this, _1));
+
+ shared_ptr<const Interest> interestToExpress(new Interest(interest));
+
+ ioService_->post(bind(&Face::asyncExpressInterest, this, interestToExpress, onData, onTimeout));
+
+ return reinterpret_cast<const PendingInterestId*>(interestToExpress.get());
+}
+
+const PendingInterestId*
+Face::expressInterest(const Name& name,
+ const Interest &tmpl,
+ const OnData& onData, const OnTimeout& onTimeout/* = OnTimeout()*/)
+{
+ return expressInterest(Interest(name,
+ tmpl.getMinSuffixComponents(),
+ tmpl.getMaxSuffixComponents(),
+ tmpl.getExclude(),
+ tmpl.getChildSelector(),
+ tmpl.getMustBeFresh(),
+ tmpl.getScope(),
+ tmpl.getInterestLifetime()),
+ onData, onTimeout);
+}
+
+void
+Face::asyncExpressInterest(const shared_ptr<const Interest> &interest,
+ const OnData& onData, const OnTimeout& onTimeout)
+{
+ pendingInterestTable_.push_back(shared_ptr<PendingInterest>(new PendingInterest
+ (interest, onData, onTimeout)));
+
+ transport_->send(interest->wireEncode());
+
+ if (!pitTimeoutCheckTimerActive_) {
+ pitTimeoutCheckTimerActive_ = true;
+ pitTimeoutCheckTimer_->expires_from_now(boost::posix_time::milliseconds(100));
+ pitTimeoutCheckTimer_->async_wait(bind(&Face::checkPitExpire, this));
+ }
+}
+
+void
+Face::put(const Data &data)
+{
+ if (!transport_->isConnected())
+ transport_->connect(*ioService_,
+ bind(&Face::onReceiveElement, this, _1));
+
+ transport_->send(data.wireEncode());
+}
+
+
+void
+Face::removePendingInterest(const PendingInterestId *pendingInterestId)
+{
+ ioService_->post(bind(&Face::asyncRemovePendingInterest, this, pendingInterestId));
+}
+
+
+void
+Face::asyncRemovePendingInterest(const PendingInterestId *pendingInterestId)
+{
+ pendingInterestTable_.remove_if(MatchPendingInterestId(pendingInterestId));
+}
+
+const RegisteredPrefixId*
+Face::setInterestFilter(const Name& prefix,
+ const OnInterest& onInterest,
+ const OnSetInterestFilterFailed& onSetInterestFilterFailed)
+{
+ shared_ptr<RegisteredPrefix> prefixToRegister(new RegisteredPrefix(prefix, onInterest));
+
+ m_fwController->selfRegisterPrefix(prefixToRegister->getPrefix(),
+ bind(&RegisteredPrefixTable::push_back, ®isteredPrefixTable_, prefixToRegister),
+ bind(onSetInterestFilterFailed, prefixToRegister->getPrefix(), _1));
+
+ return reinterpret_cast<const RegisteredPrefixId*>(prefixToRegister.get());
+}
+
+void
+Face::unsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
+{
+ ioService_->post(bind(&Face::asyncUnsetInterestFilter, this, registeredPrefixId));
+}
+
+void
+Face::asyncUnsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
+{
+ RegisteredPrefixTable::iterator i = std::find_if(registeredPrefixTable_.begin(), registeredPrefixTable_.end(),
+ MatchRegisteredPrefixId(registeredPrefixId));
+ if (i != registeredPrefixTable_.end())
+ {
+ m_fwController->selfDeregisterPrefix((*i)->getPrefix(),
+ bind(&RegisteredPrefixTable::erase, ®isteredPrefixTable_, i),
+ Controller::FailCallback());
+ }
+
+ // there cannot be two registered prefixes with the same id. if there are, then something is broken
+}
+
+void
+Face::processEvents(Milliseconds timeout/* = 0 */, bool keepThread/* = false*/)
+{
+ try
+ {
+ if (timeout < 0)
+ {
+ // do not block if timeout is negative, but process pending events
+ ioService_->poll();
+ return;
+ }
+
+ if (timeout > 0)
+ {
+ processEventsTimeoutTimer_->expires_from_now(boost::posix_time::milliseconds(timeout));
+ processEventsTimeoutTimer_->async_wait(&fireProcessEventsTimeout);
+ }
+
+ if (keepThread) {
+ // work will ensure that ioService_ is running until work object exists
+ ioServiceWork_ = make_shared<boost::asio::io_service::work>(boost::ref(*ioService_));
+ }
+
+ ioService_->run();
+ ioService_->reset(); // so it is possible to run processEvents again (if necessary)
+ }
+ catch(Face::ProcessEventsTimeout &)
+ {
+ // break
+ ioService_->reset();
+ }
+ catch(const std::exception &)
+ {
+ ioService_->reset();
+ pendingInterestTable_.clear();
+ registeredPrefixTable_.clear();
+ throw;
+ }
}
void
Face::shutdown()
{
- node_.shutdown();
+ pendingInterestTable_.clear();
+ registeredPrefixTable_.clear();
+
+ transport_->close();
+ pitTimeoutCheckTimer_->cancel();
+ processEventsTimeoutTimer_->cancel();
+ pitTimeoutCheckTimerActive_ = false;
}
+void
+Face::fireProcessEventsTimeout(const boost::system::error_code& error)
+{
+ if (!error) // can fire for some other reason, e.g., cancelled
+ throw Face::ProcessEventsTimeout();
}
+
+void
+Face::checkPitExpire()
+{
+ // Check for PIT entry timeouts. Go backwards through the list so we can erase entries.
+ MillisecondsSince1970 nowMilliseconds = getNowMilliseconds();
+
+ PendingInterestTable::iterator i = pendingInterestTable_.begin();
+ while (i != pendingInterestTable_.end())
+ {
+ if ((*i)->isTimedOut(nowMilliseconds))
+ {
+ // Save the PendingInterest and remove it from the PIT. Then call the callback.
+ shared_ptr<PendingInterest> pendingInterest = *i;
+
+ i = pendingInterestTable_.erase(i);
+
+ pendingInterest->callTimeout();
+ }
+ else
+ ++i;
+ }
+
+ if (!pendingInterestTable_.empty()) {
+ pitTimeoutCheckTimerActive_ = true;
+
+ pitTimeoutCheckTimer_->expires_from_now(boost::posix_time::milliseconds(100));
+ pitTimeoutCheckTimer_->async_wait(bind(&Face::checkPitExpire, this));
+ }
+ else {
+ pitTimeoutCheckTimerActive_ = false;
+
+ if (registeredPrefixTable_.empty()) {
+ transport_->close();
+ if (!ioServiceWork_) {
+ processEventsTimeoutTimer_->cancel();
+ }
+ }
+ }
+}
+
+
+void
+Face::onReceiveElement(const Block &block)
+{
+ if (block.type() == Tlv::Interest)
+ {
+ shared_ptr<Interest> interest(new Interest());
+ interest->wireDecode(block);
+
+ RegisteredPrefixTable::iterator entry = getEntryForRegisteredPrefix(interest->getName());
+ if (entry != registeredPrefixTable_.end()) {
+ (*entry)->getOnInterest()((*entry)->getPrefix(), *interest);
+ }
+ }
+ else if (block.type() == Tlv::Data)
+ {
+ shared_ptr<Data> data(new Data());
+ data->wireDecode(block);
+
+ PendingInterestTable::iterator entry = getEntryIndexForExpressedInterest(data->getName());
+ if (entry != pendingInterestTable_.end()) {
+ // Copy pointers to the needed objects and remove the PIT entry before the calling the callback.
+ const OnData onData = (*entry)->getOnData();
+ const shared_ptr<const Interest> interest = (*entry)->getInterest();
+ pendingInterestTable_.erase(entry);
+
+ if (onData) {
+ onData(*interest, *data);
+ }
+
+ if (pendingInterestTable_.empty()) {
+ pitTimeoutCheckTimer_->cancel(); // this will cause checkPitExpire invocation
+ }
+ }
+ }
+}
+
+Face::PendingInterestTable::iterator
+Face::getEntryIndexForExpressedInterest(const Name& name)
+{
+ for (PendingInterestTable::iterator i = pendingInterestTable_.begin ();
+ i != pendingInterestTable_.end(); ++i)
+ {
+ if ((*i)->getInterest()->matchesName(name))
+ {
+ return i;
+ }
+ }
+
+ return pendingInterestTable_.end();
+}
+
+Face::RegisteredPrefixTable::iterator
+Face::getEntryForRegisteredPrefix(const Name& name)
+{
+ RegisteredPrefixTable::iterator longestPrefix = registeredPrefixTable_.end();
+
+ for (RegisteredPrefixTable::iterator i = registeredPrefixTable_.begin();
+ i != registeredPrefixTable_.end();
+ ++i)
+ {
+ if (longestPrefix == registeredPrefixTable_.end() ||
+ (*i)->getPrefix().size() > (*longestPrefix)->getPrefix().size())
+ {
+ longestPrefix = i;
+ }
+ }
+ return longestPrefix;
+}
+
+} // namespace ndn