Added PitEntry and make expressInterest use the PIT.
diff --git a/ndn-cpp/node.cpp b/ndn-cpp/node.cpp
index fed4c8e..26a6ecd 100644
--- a/ndn-cpp/node.cpp
+++ b/ndn-cpp/node.cpp
@@ -13,14 +13,52 @@
namespace ndn {
+Node::PitEntry::PitEntry(const Name &name, Closure *closure)
+: interest_(name), interestStructIsStale_(true), closure_(closure)
+{
+ if (interest_.getInterestLifetimeMilliseconds() >= 0.0)
+ timeoutTime_ = ::clock() + (clock_t)((interest_.getInterestLifetimeMilliseconds() / 1000.0) * (double)CLOCKS_PER_SEC);
+ else
+ // No timeout.
+ timeoutTime_ = 0;
+}
+
+const struct ndn_Interest &Node::PitEntry::getInterestStruct()
+{
+ if (interestStructIsStale_) {
+ nameComponents_.reserve(interest_.getName().getComponentCount());
+ excludeEntries_.reserve(interest_.getExclude().getEntryCount());
+ ndn_Interest_init
+ (&interestStruct_, &nameComponents_[0], nameComponents_.capacity(), &excludeEntries_[0], excludeEntries_.capacity());
+ interest_.get(interestStruct_);
+
+ interestStructIsStale_ = false;
+ }
+
+ return interestStruct_;
+}
+
void Node::expressInterest(const Name &name, Closure *closure, const Interest *interestTemplate)
{
- Interest interest(name);
- shared_ptr<vector<unsigned char> > encoding = interest.wireEncode();
-
- // TODO: This should go in the PIT.
- tempClosure_ = closure;
+ shared_ptr<PitEntry> pitEntry(new PitEntry(name, closure));
+ if (interestTemplate) {
+ pitEntry->getInterest().setMinSuffixComponents(interestTemplate->getMinSuffixComponents());
+ pitEntry->getInterest().setMaxSuffixComponents(interestTemplate->getMaxSuffixComponents());
+ pitEntry->getInterest().getPublisherPublicKeyDigest() = interestTemplate->getPublisherPublicKeyDigest();
+ pitEntry->getInterest().getExclude() = interestTemplate->getExclude();
+ pitEntry->getInterest().setChildSelector(interestTemplate->getChildSelector());
+ pitEntry->getInterest().setAnswerOriginKind(interestTemplate->getAnswerOriginKind());
+ pitEntry->getInterest().setScope(interestTemplate->getScope());
+ pitEntry->getInterest().setInterestLifetimeMilliseconds(interestTemplate->getInterestLifetimeMilliseconds());
+ }
+ else
+ pitEntry->getInterest().setInterestLifetimeMilliseconds(4000.0); // default interest timeout value.
+ pit_.push_back(pitEntry);
+
+ shared_ptr<vector<unsigned char> > encoding = pitEntry->getInterest().wireEncode();
+
+ // TODO: Check if we are already connected.
transport_->connect(*this);
transport_->send(*encoding);
}
@@ -38,9 +76,16 @@
shared_ptr<Data> data(new Data());
data->wireDecode(element, elementLength);
- shared_ptr<Interest> dummyInterest;
- UpcallInfo upcallInfo(this, dummyInterest, 0, data);
- tempClosure_->upcall(UPCALL_DATA, upcallInfo);
+ int iPitEntry = getEntryIndexForExpressedInterest(data->getName());
+ if (iPitEntry >= 0) {
+ shared_ptr<Interest> interestCopy(new Interest(pit_[iPitEntry]->getInterest()));
+ UpcallInfo upcallInfo(this, interestCopy, 0, data);
+
+ // Remove the PIT entry before the calling the callback.
+ Closure *closure = pit_[iPitEntry]->getClosure();
+ pit_.erase(pit_.begin() + iPitEntry);
+ closure->upcall(UPCALL_DATA, upcallInfo);
+ }
}
}
@@ -49,4 +94,26 @@
transport_->close();
}
+int Node::getEntryIndexForExpressedInterest(const Name &name)
+{
+ // TODO: Doesn't this belong in the Name class?
+ vector<struct ndn_NameComponent> nameComponents;
+ nameComponents.reserve(name.getComponentCount());
+ struct ndn_Name nameStruct;
+ ndn_Name_init(&nameStruct, &nameComponents[0], nameComponents.capacity());
+ name.get(nameStruct);
+
+ int iResult = -1;
+
+ for (unsigned int i = 0; i < pit_.size(); ++i) {
+ if (ndn_Interest_matchesName((struct ndn_Interest *)&pit_[i]->getInterestStruct(), &nameStruct)) {
+ if (iResult < 0 ||
+ pit_[i]->getInterest().getName().getComponentCount() > pit_[iResult]->getInterest().getName().getComponentCount())
+ iResult = i;
+ }
+ }
+
+ return iResult;
+}
+
}
diff --git a/ndn-cpp/node.hpp b/ndn-cpp/node.hpp
index 789a584..a9195d3 100644
--- a/ndn-cpp/node.hpp
+++ b/ndn-cpp/node.hpp
@@ -6,6 +6,7 @@
#ifndef NDN_NODE_HPP
#define NDN_NODE_HPP
+#include <time.h>
#include "interest.hpp"
#include "closure.hpp"
#include "transport/udp-transport.hpp"
@@ -24,7 +25,7 @@
* @param transport A pointer to a Transport object used for communication.
*/
Node(const char *host, unsigned short port, const ptr_lib::shared_ptr<Transport> &transport)
- : host_(host), port_(port), transport_(transport), tempClosure_(0)
+ : host_(host), port_(port), transport_(transport)
{
}
@@ -34,7 +35,7 @@
* @param port The port of the NDN hub.
*/
Node(const char *host, unsigned short port)
- : host_(host), port_(port), transport_(new UdpTransport()), tempClosure_(0)
+ : host_(host), port_(port), transport_(new UdpTransport())
{
}
@@ -43,7 +44,7 @@
* @param host The host of the NDN hub.
*/
Node(const char *host)
- : host_(host), port_(9695), transport_(new UdpTransport()), tempClosure_(0)
+ : host_(host), port_(9695), transport_(new UdpTransport())
{
}
@@ -83,10 +84,60 @@
void shutdown();
private:
+ class PitEntry {
+ public:
+ /**
+ * Create a new PitEntry and set the timeoutTime_ based on the current time and the interest lifetime.
+ * @param name The name for the interest. You can use the non-const getInterest() to set other fields.
+ * (We do it like this to avoid invoking the Interest copy constructor.)
+ * @param closure A pointer to the closure with the callbacks to call on match.
+ * The caller must manage the memory for the Closure. This will not try to delete it.
+ */
+ PitEntry(const Name &name, Closure *closure);
+
+ Interest &getInterest()
+ {
+ // Assume that the caller will modify interest_, so mark it stale.
+ interestStructIsStale_ = true;
+ return interest_;
+ }
+
+ Closure *getClosure() { return closure_; }
+
+ /**
+ * Get the struct ndn_Interest for the interest_. If interestStructIsStale_, then this will
+ * re-build from interest_.
+ * WARNING: Assume that this PitEntry was created with new, so that no copy constructor is invoked between calls.
+ * This class is private to Node and only used by its methods, so this should be OK.
+ * TODO: Doesn't this functionality belong in the Interest class?
+ * @return A reference to the ndn_Interest struct.
+ * WARNING: The resulting pointers in are invalid uses getInterest() to manipulate the object which could reallocate memory.
+ */
+ const struct ndn_Interest &getInterestStruct();
+
+ private:
+ Interest interest_;
+ std::vector<struct ndn_NameComponent> nameComponents_;
+ std::vector<struct ndn_ExcludeEntry> excludeEntries_;
+ struct ndn_Interest interestStruct_;
+ bool interestStructIsStale_;
+
+ Closure *closure_;
+ clock_t timeoutTime_; /**< The clock time when the interest times out, of 0 for none. */
+ };
+
+ /**
+ * Find the entry from the pit_ where the name conforms to the entry's interest selectors, and
+ * the entry interest name is the longest that matches name.
+ * @param name The name to find the interest for (from the incoming data packet).
+ * @return The index in pit_ of the pit entry, or -1 if not found.
+ */
+ int getEntryIndexForExpressedInterest(const Name &name);
+
ptr_lib::shared_ptr<Transport> transport_;
+ std::vector<ptr_lib::shared_ptr<PitEntry> > pit_;
std::string host_;
unsigned short port_;
- Closure *tempClosure_;
};
}
diff --git a/tests/test-get-async.cpp b/tests/test-get-async.cpp
index 62cc2e5..94f3455 100644
--- a/tests/test-get-async.cpp
+++ b/tests/test-get-async.cpp
@@ -17,14 +17,14 @@
class MyClosure : public Closure {
public:
MyClosure()
- : gotContent_(false)
+ : gotContentCount_(0)
{
}
virtual UpcallResult upcall(UpcallKind kind, UpcallInfo &upcallInfo)
{
if (kind == UPCALL_DATA || kind == UPCALL_DATA_UNVERIFIED) {
- gotContent_ = true;
+ ++gotContentCount_;
cout << "Got data packet with name " << upcallInfo.getData()->getName().to_uri() << endl;
for (unsigned int i = 0; i < upcallInfo.getData()->getContent().size(); ++i)
cout << upcallInfo.getData()->getContent()[i];
@@ -36,7 +36,7 @@
return CLOSURE_RESULT_OK;
}
- bool gotContent_;
+ int gotContentCount_;
};
int main(int argc, char** argv)
@@ -44,10 +44,18 @@
try {
MyClosure closure;
Face face("E.hub.ndn.ucla.edu");
- face.expressInterest(Name("/ndn/ucla.edu/apps/ndn-js-test/hello.txt/level2/%FD%05%0B%16%7D%95%0E"), &closure);
+ Name name1("/ndn/ucla.edu/apps/ndn-js-test/hello.txt/level2/%FD%05%0B%16%7D%95%0E");
+ cout << "Express name " << name1.toUri() << endl;
+ face.expressInterest(name1, &closure);
+#if 0
+ Name name2("/ndn/ucla.edu/apps/lwndn-test/howdy.txt/%FD%05%05%E8%0C%CE%1D");
+ cout << "Express name " << name2.toUri() << endl;
+ face.expressInterest(name2, &closure);
+#endif
+
// The main event loop.
- while (!closure.gotContent_) {
+ while (closure.gotContentCount_ < 1) {
face.processEvents();
// We need to sleep for a few milliseconds so we don't use 100% of the CPU.
usleep(10000);