model+ndn.cxx+test: Finishing implementation of ApiFace (now timeouts are working as well)
Also, adding a basic test case to test ApiFace
Refs #1005 (http://redmine.named-data.net/)
diff --git a/ndn.cxx/detail/filter-entry.h b/ndn.cxx/detail/filter-entry.h
deleted file mode 100644
index 97b9a14..0000000
--- a/ndn.cxx/detail/filter-entry.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- * Alexander Afanasyev
- *
- * GNU v3.0 license, See the LICENSE file for more information
- *
- * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
- */
-
-#ifndef NDN_NDNCXX_DETAIL_FILTER_ENTRY_H
-#define NDN_NDNCXX_DETAIL_FILTER_ENTRY_H
-
-#include <ns3/ndnSIM/utils/trie/trie-with-policy.h>
-#include <ns3/ndnSIM/utils/trie/counting-policy.h>
-
-namespace ns3 {
-namespace ndn {
-
-template<class Callback, class Payload>
-struct FilterEntry : public ns3::SimpleRefCount< FilterEntry<Callback, Payload> >
-{
-public:
- FilterEntry (Ptr<const Payload> payload)
- : m_payload (payload)
- { }
-
- void
- AddCallback (Callback callback)
- {
- m_callback = callback;
- }
-
- void
- ClearCallback ()
- {
- m_callback = Callback ();
- }
-
- Ptr<const Payload>
- GetPayload () const
- {
- return m_payload;
- }
-
-public:
- Callback m_callback;
- Ptr<const Payload> m_payload;
-};
-
-
-template<class Callback, class Payload>
-struct FilterEntryContainer :
- public ns3::ndn::ndnSIM::trie_with_policy<ns3::ndn::Name,
- ns3::ndn::ndnSIM::smart_pointer_payload_traits< FilterEntry<Callback, Payload> >,
- ns3::ndn::ndnSIM::counting_policy_traits>
-{
-};
-
-} // ndn
-} // ns3
-
-#endif // NDN_NDNCXX_DETAIL_FILTER_ENTRY_H
diff --git a/ndn.cxx/detail/pending-interests-container.h b/ndn.cxx/detail/pending-interests-container.h
new file mode 100644
index 0000000..4d96ed4
--- /dev/null
+++ b/ndn.cxx/detail/pending-interests-container.h
@@ -0,0 +1,66 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * GNU v3.0 license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_NDNCXX_DETAIL_PENDING_INTEREST_CONTAINER_H
+#define NDN_NDNCXX_DETAIL_PENDING_INTEREST_CONTAINER_H
+
+#include <ns3/ndnSIM/utils/trie/trie-with-policy.h>
+#include "timeouts-policy.h"
+
+namespace ns3 {
+namespace ndn {
+namespace detail {
+
+struct PendingInterestEntry : public SimpleRefCount< PendingInterestEntry >
+{
+public:
+ PendingInterestEntry (Ptr<const Interest> interest)
+ : m_interest (interest)
+ { }
+
+ void
+ AddCallbacks (ApiFace::DataCallback onData, ApiFace::TimeoutCallback onTimeout)
+ {
+ m_dataCallback = onData;
+ m_timeoutCallback = onTimeout;
+ }
+
+ void
+ ClearCallbacks ()
+ {
+ m_dataCallback = ApiFace::DataCallback ();
+ m_timeoutCallback = ApiFace::TimeoutCallback ();
+ }
+
+ Ptr<const Interest>
+ GetInterest () const
+ {
+ return m_interest;
+ }
+
+public:
+ ApiFace::DataCallback m_dataCallback;
+ ApiFace::TimeoutCallback m_timeoutCallback;
+ Ptr<const Interest> m_interest;
+};
+
+
+struct PendingInterestContainer :
+ public ndnSIM::trie_with_policy<Name,
+ ndnSIM::smart_pointer_payload_traits< PendingInterestEntry >,
+ timeouts_policy_traits>
+{
+};
+
+} // detail
+} // ndn
+} // ns3
+
+#endif // NDN_NDNCXX_DETAIL_PENDING_INTEREST_CONTAINER_H
diff --git a/ndn.cxx/detail/registered-prefix-container.h b/ndn.cxx/detail/registered-prefix-container.h
new file mode 100644
index 0000000..2e6c151
--- /dev/null
+++ b/ndn.cxx/detail/registered-prefix-container.h
@@ -0,0 +1,63 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * GNU v3.0 license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_NDNCXX_DETAIL_REGISTERED_PREFIX_CONTAINER_H
+#define NDN_NDNCXX_DETAIL_REGISTERED_PREFIX_CONTAINER_H
+
+#include <ns3/ndnSIM/utils/trie/trie-with-policy.h>
+#include <ns3/ndnSIM/utils/trie/counting-policy.h>
+
+namespace ns3 {
+namespace ndn {
+namespace detail {
+
+struct RegisteredPrefixEntry : public SimpleRefCount< RegisteredPrefixEntry >
+{
+public:
+ RegisteredPrefixEntry (Ptr<const Name> prefix)
+ : m_prefix (prefix)
+ { }
+
+ void
+ AddCallback (ApiFace::InterestCallback callback)
+ {
+ m_callback = callback;
+ }
+
+ void
+ ClearCallback ()
+ {
+ m_callback = ApiFace::InterestCallback ();
+ }
+
+ Ptr<const Name>
+ GetPrefix () const
+ {
+ return m_prefix;
+ }
+
+public:
+ ApiFace::InterestCallback m_callback;
+ Ptr<const Name> m_prefix;
+};
+
+
+struct RegisteredPrefixContainer :
+ public ndnSIM::trie_with_policy<Name,
+ ndnSIM::smart_pointer_payload_traits< RegisteredPrefixEntry >,
+ ndnSIM::counting_policy_traits>
+{
+};
+
+} // detail
+} // ndn
+} // ns3
+
+#endif // NDN_NDNCXX_DETAIL_REGISTERED_PREFIX_CONTAINER_H
diff --git a/ndn.cxx/detail/timeouts-policy.h b/ndn.cxx/detail/timeouts-policy.h
new file mode 100644
index 0000000..7398d44
--- /dev/null
+++ b/ndn.cxx/detail/timeouts-policy.h
@@ -0,0 +1,167 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * GNU v3.0 license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_NDNCXX_DETAIL_TIMEOUTS_POLICY_H_
+#define NDN_NDNCXX_DETAIL_TIMEOUTS_POLICY_H_
+
+#include <boost/intrusive/options.hpp>
+#include <boost/intrusive/list.hpp>
+
+#include <ns3/nstime.h>
+#include <ns3/simulator.h>
+
+namespace ns3 {
+namespace ndn {
+namespace detail {
+
+/**
+ * @brief Traits for timeouts policy
+ */
+struct timeouts_policy_traits
+{
+ /// @brief Name that can be used to identify the policy (for NS-3 object model and logging)
+ static std::string GetName () { return "Timeouts"; }
+
+ struct policy_hook_type : public boost::intrusive::set_member_hook<> { Time timeWhenShouldExpire; };
+
+ template<class Container>
+ struct container_hook
+ {
+ typedef boost::intrusive::member_hook< Container,
+ policy_hook_type,
+ &Container::policy_hook_ > type;
+ };
+
+ template<class Base,
+ class Container,
+ class Hook>
+ struct policy
+ {
+ static Time& get_timeout (typename Container::iterator item)
+ {
+ return static_cast<typename policy_container::value_traits::hook_type*>
+ (policy_container::value_traits::to_node_ptr(*item))->timeWhenShouldExpire;
+ }
+
+ static const Time& get_timeout (typename Container::const_iterator item)
+ {
+ return static_cast<const typename policy_container::value_traits::hook_type*>
+ (policy_container::value_traits::to_node_ptr(*item))->timeWhenShouldExpire;
+ }
+
+ template<class Key>
+ struct MemberHookLess
+ {
+ bool operator () (const Key &a, const Key &b) const
+ {
+ return get_timeout (&a) < get_timeout (&b);
+ }
+ };
+
+ typedef boost::intrusive::multiset< Container,
+ boost::intrusive::compare< MemberHookLess< Container > >,
+ Hook > policy_container;
+
+
+ class type : public policy_container
+ {
+ public:
+ typedef policy policy_base; // to get access to get_timeout methods from outside
+ typedef Container parent_trie;
+
+ type (Base &base)
+ : m_base (base)
+ {
+ }
+
+ inline void
+ update (typename parent_trie::iterator item)
+ {
+ // do nothing
+ }
+
+ inline bool
+ insert (typename parent_trie::iterator item)
+ {
+ Time timeout = item->payload ()->GetInterest ()->GetInterestLifetime ();
+ if (timeout.IsZero ()) timeout = Seconds (4.0);
+
+ get_timeout (item) = Simulator::Now () + timeout;
+ policy_container::insert (*item);
+
+ if (policy_container::s_iterator_to (*item) == policy_container::begin ())
+ {
+ if (m_timeoutEvent.IsRunning ())
+ {
+ Simulator::Remove (m_timeoutEvent); // just canceling would not clean up list of events
+ }
+
+ m_timeoutEvent = Simulator::Schedule (timeout, &type::ProcessTimeoutEntry, this, item);
+ }
+
+ return true;
+ }
+
+ inline void
+ lookup (typename parent_trie::iterator item)
+ {
+ // do nothing. it's random policy
+ }
+
+ inline void
+ erase (typename parent_trie::iterator item)
+ {
+ if (policy_container::s_iterator_to (*item) == policy_container::begin ())
+ {
+ if (m_timeoutEvent.IsRunning ())
+ {
+ Simulator::Remove (m_timeoutEvent); // just canceling would not clean up list of events
+ }
+ }
+
+ // erase only if freshness is non zero (otherwise an item is not in the policy
+ policy_container::erase (policy_container::s_iterator_to (*item));
+
+ if (!policy_container::empty ())
+ {
+ Time timeout = get_timeout (&*policy_container::begin ()) - Simulator::Now ();
+ m_timeoutEvent = Simulator::Schedule (timeout, &type::ProcessTimeoutEntry, this, &*policy_container::begin ());
+ }
+ }
+
+ inline void
+ clear ()
+ {
+ policy_container::clear ();
+ }
+
+ inline void
+ ProcessTimeoutEntry (typename parent_trie::iterator item)
+ {
+ item->payload ()->m_timeoutCallback (item->payload ()->GetInterest ());
+
+ m_base.erase (item);
+ }
+
+ private:
+ type () : m_base (*((Base*)0)) { };
+
+ private:
+ Base &m_base;
+ EventId m_timeoutEvent;
+ };
+ };
+};
+
+} // detail
+} // ndn
+} // ns3
+
+#endif // NDN_NDNCXX_DETAIL_TIMEOUTS_STATS_POLICY_H
diff --git a/ndn.cxx/ndn-api-face.cc b/ndn.cxx/ndn-api-face.cc
index 4c7cc10..6adfe99 100644
--- a/ndn.cxx/ndn-api-face.cc
+++ b/ndn.cxx/ndn-api-face.cc
@@ -19,7 +19,8 @@
*/
#include "ndn-api-face.h"
-#include "detail/filter-entry.h"
+#include "detail/pending-interests-container.h"
+#include "detail/registered-prefix-container.h"
#include <ns3/random-variable.h>
@@ -41,6 +42,8 @@
namespace ns3 {
namespace ndn {
+using namespace detail;
+
class ApiFacePriv
{
public:
@@ -51,8 +54,8 @@
ns3::UniformVariable m_rand; // nonce generator
- FilterEntryContainer<ApiFace::DataCallback, Interest> m_pendingInterests;
- FilterEntryContainer<ApiFace::InterestCallback, Name> m_expectedInterests;
+ PendingInterestContainer m_pendingInterests;
+ RegisteredPrefixContainer m_expectedInterests;
};
@@ -74,6 +77,24 @@
}
void
+ApiFace::Shutdown ()
+{
+ NS_LOG_FUNCTION (this);
+
+ if (!IsUp ())
+ {
+ return;
+ }
+
+ this->SetUp (false);
+
+ m_this->m_pendingInterests.clear ();
+ m_this->m_expectedInterests.clear ();
+
+ GetNode ()->GetObject<L3Protocol> ()->RemoveFace (this);
+}
+
+void
ApiFace::ExpressInterest (Ptr<Interest> interest,
DataCallback onData,
TimeoutCallback onTimeout/* = MakeNullCallback< void, Ptr<Interest> > ()*/)
@@ -86,16 +107,15 @@
}
// Record the callback
- FilterEntryContainer<DataCallback, Interest>::iterator entry =
- m_this->m_pendingInterests.find_exact (interest->GetName ());
+ PendingInterestContainer::iterator entry = m_this->m_pendingInterests.find_exact (interest->GetName ());
if (entry == m_this->m_pendingInterests.end ())
{
- pair<FilterEntryContainer<DataCallback, Interest>::iterator, bool> status =
- m_this->m_pendingInterests.insert (interest->GetName (), Create< FilterEntry<DataCallback, Interest> > (interest));
+ pair<PendingInterestContainer::iterator, bool> status =
+ m_this->m_pendingInterests.insert (interest->GetName (), Create <PendingInterestEntry> (interest));
entry = status.first;
}
- entry->payload ()->AddCallback (onData);
+ entry->payload ()->AddCallbacks (onData, onTimeout);
ReceiveInterest (interest);
}
@@ -105,11 +125,11 @@
{
NS_LOG_DEBUG ("== setInterestFilter " << *prefix << " (" << GetNode ()->GetId () << ")");
- FilterEntryContainer<InterestCallback, Name>::iterator entry = m_this->m_expectedInterests.find_exact (*prefix);
+ RegisteredPrefixContainer::iterator entry = m_this->m_expectedInterests.find_exact (*prefix);
if (entry == m_this->m_expectedInterests.end ())
{
- pair<FilterEntryContainer<InterestCallback, Name>::iterator, bool> status =
- m_this->m_expectedInterests.insert (*prefix, Create < FilterEntry<InterestCallback, Name> > (prefix));
+ pair<RegisteredPrefixContainer::iterator, bool> status =
+ m_this->m_expectedInterests.insert (*prefix, Create < RegisteredPrefixEntry > (prefix));
entry = status.first;
}
@@ -125,7 +145,7 @@
void
ApiFace::ClearInterestFilter (Ptr<const Name> prefix)
{
- FilterEntryContainer<InterestCallback, Name>::iterator entry = m_this->m_expectedInterests.find_exact (*prefix);
+ RegisteredPrefixContainer::iterator entry = m_this->m_expectedInterests.find_exact (*prefix);
if (entry == m_this->m_expectedInterests.end ())
return;
@@ -161,14 +181,13 @@
}
// the app cannot set several filters for the same prefix
- FilterEntryContainer<InterestCallback, Name>::iterator entry =
- m_this->m_expectedInterests.longest_prefix_match (interest->GetName ());
+ RegisteredPrefixContainer::iterator entry = m_this->m_expectedInterests.longest_prefix_match (interest->GetName ());
if (entry == m_this->m_expectedInterests.end ())
{
return false;
}
- entry->payload ()->m_callback (entry->payload ()->GetPayload (), interest);
+ entry->payload ()->m_callback (entry->payload ()->GetPrefix (), interest);
return true;
}
@@ -186,8 +205,7 @@
return false;
}
- FilterEntryContainer<DataCallback, Interest>::iterator entry =
- m_this->m_pendingInterests.longest_prefix_match (data->GetName ());
+ PendingInterestContainer::iterator entry = m_this->m_pendingInterests.longest_prefix_match (data->GetName ());
if (entry == m_this->m_pendingInterests.end ())
{
return false;
@@ -195,7 +213,7 @@
while (entry != m_this->m_pendingInterests.end ())
{
- entry->payload ()->m_callback (entry->payload ()->GetPayload (), data);
+ entry->payload ()->m_dataCallback (entry->payload ()->GetInterest (), data);
m_this->m_pendingInterests.erase (entry);
entry = m_this->m_pendingInterests.longest_prefix_match (data->GetName ());
diff --git a/ndn.cxx/ndn-api-face.h b/ndn.cxx/ndn-api-face.h
index 8c589bb..160540e 100644
--- a/ndn.cxx/ndn-api-face.h
+++ b/ndn.cxx/ndn-api-face.h
@@ -56,6 +56,12 @@
~ApiFace ();
/**
+ * @brief Shutdown the API face
+ */
+ void
+ Shutdown ();
+
+ /**
* @brief Express Interest
*
* @param name the Interest name