First steps in CCNx packet coding. ccnx_encode* routines rewritten in NS3 style (using NS3::Buffer)
diff --git a/in-progress/ccnx-contentstore.cc b/in-progress/ccnx-contentstore.cc
new file mode 100644
index 0000000..61d6452
--- /dev/null
+++ b/in-progress/ccnx-contentstore.cc
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Ilya Moiseenko <iliamo@cs.ucla.edu>
+ */
+
+#include "ndn_contentstore.h"
+
+namespace ns3
+{
+namespace NDNabstraction
+{
+
+ContentStore::ContentStore( int maxSize )
+: m_maxSize(maxSize) { }
+
+
+ContentStore::~ContentStore( )
+{ }
+
+//Find corresponding CS entry for the given content name
+CsEntry*
+ContentStore::Lookup(const char *prefix )
+{
+ CriticalSection section(m_csMutex);
+
+ struct CsEntry *result = NULL;
+
+ HASH_FIND_STR (m_contentStore, prefix, result);
+
+ if(result != NULL)
+ Promote (*result);
+
+ return result;
+}
+
+
+
+//Add entry to content store, if content store is full, use LRU replacement
+void
+ContentStore::Add( const char *contentName, int contentSize )
+{
+ CriticalSection section(m_csMutex);
+
+ // removing the old record
+ struct CsEntry *tmp = NULL;
+ HASH_FIND_STR (m_contentStore, contentName, tmp);
+ HASH_DELETE (hh, m_contentStore,tmp);
+ //free(tmp);
+
+ int size = (int)HASH_COUNT(m_contentStore);
+
+ if(size == m_maxSize )
+ {
+ CsEntry *entry = m_LRU.back();
+ HASH_DELETE (hh, m_contentStore,entry);//_cs.erase( entry->contentName );
+ m_LRU.pop_back( );
+ }
+
+ struct CsEntry *ce = (struct CsEntry*)malloc(sizeof(struct CsEntry));
+ ce->contentName = (char*)contentName;
+ ce->contentSize = contentSize;
+
+ //_cs[ contentName ] = ce;
+ HASH_ADD_KEYPTR (hh, m_contentStore, ce->contentName, strlen(ce->contentName), ce);
+
+ //CsEntry *ce_in_hash = &(_cs[ contentName ]);
+ struct CsEntry *ce_in_hash = NULL;
+ HASH_FIND_STR (m_contentStore, contentName, ce_in_hash);
+ m_LRU.push_front( ce_in_hash );
+ ce_in_hash->lruPosition = m_LRU.begin( );
+}
+
+
+//move the given CS entry to the head of the list
+void
+ContentStore::Promote(CsEntry &ce )
+{
+ // should not lock mutex. Otherwise deadlocks will be welcome
+ if( m_LRU.front() == &ce ) return;
+
+ //assert( *(ce.lruPosition)==&ce ); // should point to the same object
+
+ // swaping positions in _lru
+ m_LRU.erase( ce.lruPosition );
+ m_LRU.push_front( &ce );
+ ce.lruPosition = m_LRU.begin( );
+
+ //assert( *(ce.lruPosition)==&ce ); // should point to the same object
+}
+
+void
+ContentStore::Dump()
+{
+ CriticalSection section(m_csMutex);
+
+ struct CsEntry *s, *tmp;
+
+ HASH_ITER(hh, m_contentStore, s, tmp)
+ {
+ printf("-%s-", s->contentName);
+ /* ... it is safe to delete and free s here */
+ }
+
+ printf("\n");
+
+}
+}
+}
diff --git a/in-progress/ccnx-contentstore.h b/in-progress/ccnx-contentstore.h
new file mode 100644
index 0000000..7e49fb6
--- /dev/null
+++ b/in-progress/ccnx-contentstore.h
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Ilya Moiseenko <iliamo@cs.ucla.edu>
+ */
+
+#ifndef ndn_contentstore_h
+#define ndn_contentstore_h
+
+#include <ns3/system-mutex.h>
+#include <list>
+#include <string>
+#include "uthash.h"
+
+using namespace std;
+
+//size of content store
+#define NDN_CONTENT_STORE_SIZE 100
+
+namespace ns3
+{
+namespace NDNabstraction
+{
+
+class CsEntry;
+typedef list<CsEntry*>::iterator CsLruIterator;
+
+//structure for CS entry
+struct CsEntry
+{
+ char *contentName;
+ int contentSize;
+
+ CsLruIterator lruPosition;
+ UT_hash_handle hh; /* makes this structure hashable */
+};
+
+
+class ContentStore
+{
+public:
+ ContentStore( int max_size=NDN_CONTENT_STORE_SIZE );
+ virtual ~ContentStore( );
+
+ // Find corresponding CS entry for the given content name
+ CsEntry* Lookup( const char *prefix );
+ //bool isValid( const CsIterator &it ) { return it!=_cs.end(); }
+
+ // Add new content to the content store. Old content will be replaced
+ void Add( const char *contentName, int contentSize );
+
+ // Dump content store entries
+ void Dump( );
+
+protected:
+ //move the given CS entry to the head of the list
+ void Promote( CsEntry &entry );
+
+private:
+ int m_maxSize; // maximum number of entries in cache
+
+ struct CsEntry *m_contentStore; // actual content store
+ list<CsEntry*> m_LRU; // LRU index of the content store
+ SystemMutex m_csMutex; // just to make sure we are not
+};
+
+}
+}
+#endif
diff --git a/in-progress/ccnx-cs.cpp b/in-progress/ccnx-cs.cpp
new file mode 100644
index 0000000..c102cd5
--- /dev/null
+++ b/in-progress/ccnx-cs.cpp
@@ -0,0 +1,90 @@
+/*
+ * File: ndn_cs.cpp
+ * Author: cawka
+ *
+ * Created on December 15, 2010, 2:17 PM
+ */
+
+#include "ndn_cs.h"
+
+NdnCs::NdnCs( int maxSize )
+: _maxSize(maxSize) { }
+
+//NdnCs::NdnCs( constNdnCs& orig ) { }
+
+NdnCs::~NdnCs( ) { }
+
+//Find corresponding CS entry for the given content name
+CsIterator NdnCs::lookup( const string &prefix )
+{
+ QNThreadLock lock( &_csMutex );
+
+ CsIterator entry=_cs.find( prefix );
+ if( entry!=_cs.end() ) promote( entry->second );
+ return entry;
+}
+
+
+
+//Add entry to content store, if content store is full, use LRU replacement
+void NdnCs::add( const string &contentName, int contentSize )
+{
+ QNThreadLock lock( &_csMutex );
+
+ _cs.erase( contentName ); // removing the old record
+
+ if( _cs.size()==_maxSize )
+ {
+ CsEntry *entry=_lru.back();
+ _cs.erase( entry->contentName );
+ _lru.pop_back( );
+ }
+
+ CsEntry ce;
+ ce.contentName = contentName;
+ ce.contentSize = contentSize;
+
+ _cs[ contentName ] = ce;
+
+ CsEntry *ce_in_hash = &(_cs[ contentName ]);
+ _lru.push_front( ce_in_hash );
+ ce_in_hash->lruPosition = _lru.begin( );
+}
+
+
+//move the given CS entry to the head of the list
+void NdnCs::promote( CsEntry &ce )
+{
+ // should not lock mutex. Otherwise deadlocks will be welcome
+ if( _lru.front() == &ce ) return;
+
+ assert( *(ce.lruPosition)==&ce ); // should point to the same object
+
+ // swaping positions in _lru
+ _lru.erase( ce.lruPosition );
+ _lru.push_front( &ce );
+ ce.lruPosition = _lru.begin( );
+
+ assert( *(ce.lruPosition)==&ce ); // should point to the same object
+}
+
+void NdnCs::dump()
+{
+ QNThreadLock lock( &_csMutex );
+
+ for( CsRangeIterator it=_cs.begin(); it!=_cs.end(); ++it )
+ {
+ printf("-%s-", it->second.contentName.c_str() );
+ }
+
+ printf("\n");
+// list<CsEntry *>::reverse_iterator rit;
+//
+// for (rit = contentList->rbegin(); rit != contentList->rend(); rit ++)
+// {
+// temp = *rit;
+// printf("=%s=", temp->contentName);
+// }
+//
+// printf("\n");
+}
diff --git a/in-progress/ccnx-cs.h b/in-progress/ccnx-cs.h
new file mode 100644
index 0000000..096b0c0
--- /dev/null
+++ b/in-progress/ccnx-cs.h
@@ -0,0 +1,65 @@
+/*
+ * File: ndn_cs.h
+ * Author: cawka
+ *
+ * Created on December 15, 2010, 2:17 PM
+ */
+
+#ifndef NDN_CS_H
+#define NDN_CS_H
+
+#include "ndn_common.h"
+#include "hash_helper.h"
+#include <qualnet_mutex.h>
+#include <list>
+#include <string>
+
+using namespace std;
+
+class CsEntry;
+typedef list<CsEntry*>::iterator CsLruIterator;
+
+//structure for CS entry
+struct CsEntry
+{
+ string contentName;
+ int contentSize;
+
+ CsLruIterator lruPosition;
+};
+
+typedef string_key_hash_t<CsEntry>::point_iterator CsIterator;
+typedef string_key_hash_t<CsEntry>::iterator CsRangeIterator;
+
+// class implementing NDN content store
+class NdnCs
+{
+public:
+ NdnCs( int max_size=NDN_CONTENT_STORE_SIZE );
+ virtual ~NdnCs( );
+
+ // Find corresponding CS entry for the given content name
+ CsIterator lookup( const string &prefix );
+ bool isValid( const CsIterator &it ) { return it!=_cs.end(); }
+
+ // Add new content to the content store. Old content will be replaced
+ void add( const string &contentName, int contentSize );
+
+ // Dump content store entries
+ void dump( );
+
+protected:
+ //move the given CS entry to the head of the list
+ void promote( CsEntry &entry );
+
+private:
+ int _maxSize; // maximum number of entries in cache
+
+ string_key_hash_t<CsEntry> _cs; // actual content store
+
+ list<CsEntry*> _lru; // LRU index of the content store
+ QNThreadMutex _csMutex; // just to make sure we are not
+ // getting problems with multiple threads
+};
+
+#endif /* NDN_CS_H */
diff --git a/in-progress/ccnx-fib.cpp b/in-progress/ccnx-fib.cpp
new file mode 100644
index 0000000..a8adbd0
--- /dev/null
+++ b/in-progress/ccnx-fib.cpp
@@ -0,0 +1,300 @@
+/*
+ * File: ndn_fib.cpp
+ * Author: cawka
+ *
+ * Created on December 15, 2010, 1:54 PM
+ */
+
+#include "ndn.h"
+#include "ndn_fib.h"
+
+#include <node.h>
+#include <buffer.h>
+#include <network_ip.h>
+#include <partition.h>
+#include <routing_ospfv2.h>
+#include <routing_bgp.h>
+
+//#define NDN_DEBUG_OSPF 0
+//#define NDN_DEBUG_OSPF_NODES 0
+
+//#define NDN_DUMP_FIB 0
+
+
+NdnFib::NdnFib( Ndn &node ) : _node(node) { }
+
+NdnFib::~NdnFib( ) { }
+
+
+//Find corresponding FIB entry for the given content name
+//Longest match is performed
+FibIterator NdnFib::lookup( const string &name )
+{
+ string prefix=name;
+
+ FibIterator entry;
+ do
+ {
+ entry=_fib.find( prefix );
+
+ prefix = GetLongestNamePrefix( prefix );
+ } while( !isValid(entry) && prefix.size()>0 );
+
+ return entry;
+}
+
+bool NdnFibNexthopSorter::operator()( const FibNexthop &first, const FibNexthop &second )
+{
+ // Right now is a very simple logic.
+ // Probably this logic should be changed later
+ if( first. cost==NETWORK_UNREACHABLE && second.cost>=0 ) return false;
+ if( second.cost==NETWORK_UNREACHABLE && first. cost>=0 ) return true;
+ return first.cost < second.cost;
+}
+
+/**
+ * Update FIB entry
+ * If the entry exists, metric will be updated. Otherwise, new entry will be created
+ *
+ * @param name Prefix
+ * @param interfaceIndex Forwarding interface
+ * @param metric Routing metric
+ * @param nextHop Nexthop node address (IPv4)
+ * @return true if a new entry created, false otherwise
+ */
+bool NdnFib::update( const string &name, int interfaceIndex, int metric, NodeAddress nextHop )
+{
+ FibIterator entry = _fib.find( name );
+ if( isValid(entry) )
+ {
+ FibNexthopIterator nh = VALUE(entry).findNexthop( interfaceIndex );
+
+ if( !VALUE(entry).isValid(nh) )
+ {
+ nh = VALUE(entry).forwardingList.insert( VALUE(entry).forwardingList.begin(),
+ FibNexthop(interfaceIndex,nextHop,metric) );
+ }
+ else
+ {
+ nh->cost = metric;
+ nh->nextHop = nextHop;
+ }
+
+ VALUE(entry).forwardingList.sort( NdnFibNexthopSorter() );
+
+ return false;
+ }
+
+ FibEntry &new_entry = _fib[name];
+ new_entry.forwardingList.push_back( FibNexthop(interfaceIndex,nextHop,metric) );
+
+ for( int interface=0; interface < _node.getNode()->numberInterfaces; interface++ )
+ {
+ NodeAddress src = NetworkIpGetInterfaceAddress( _node.getNode(), interface );
+
+ if( isValidLink(src) && interface!=interfaceIndex )
+ {
+ new_entry.forwardingList.push_back( FibNexthop(interface,0,NETWORK_UNREACHABLE) );
+ }
+ }
+
+ return true;
+}
+
+// helper for update call
+bool NdnFib::update( NodeAddress nodeId, int metric, NodeAddress nextHop )
+{
+ ostringstream os;
+ os << (int)nodeId;
+
+ int interface = NetworkIpGetInterfaceIndexForNextHop( _node.getNode(), nextHop );
+
+ return update( os.str(), interface, metric, nextHop );
+}
+
+// helper for update call
+bool NdnFib::update( NodeAddress nodeId, int interfaceIndex, int metric, NodeAddress nextHop )
+{
+ ostringstream os;
+ os << (int)nodeId;
+
+ int interface = NetworkIpGetInterfaceIndexForNextHop( _node.getNode(), nextHop );
+
+ return update( os.str(), interface, metric, nextHop ); //unknown metric
+}
+
+/**
+ * Invalidate entries in FIB
+ */
+void NdnFib::invalidate( )
+{
+ for( FibRangeIterator fib=_fib.begin(); fib!=_fib.end(); fib++ )
+ {
+ for( FibNexthopIterator nh=VALUE(fib).forwardingList.begin(); nh!=VALUE(fib).forwardingList.end(); nh++ )
+ {
+ nh->cost = NETWORK_UNREACHABLE;
+ }
+ }
+}
+
+//compute and update STO value for Fib Entry (similar to RFC 2988)
+//for now we pick the maximum rto of all forwardings
+void FibEntry::updateSto( )
+{
+ assert( forwardingList.size() > 0 );
+
+ clocktype max = 0;
+
+ for( FibNexthopIterator it = forwardingList.begin();
+ it != forwardingList.end();
+ it++ )
+ {
+ clocktype sto = it->srtt + NDN_RTO_K * it->rttvar;
+
+ if( sto > max )
+ max = sto;
+ }
+
+ this->sto = max;
+}
+
+
+/**
+ * Updating FIB using data from OSPF
+ * @param node
+ * @param interface -2 Invalid OSPF (to purge FIB)
+ * -1 Normal OSPF
+ * 0-N SPF was calcylated using only interface `interface'
+ *
+ * @bug All local networks will always appear in routing table with cost == 1
+ */
+void NdnFib::updateFibFromOSPFv2( int interface )
+{
+ Ospfv2Data* ospf = (Ospfv2Data*)NetworkIpGetRoutingProtocol(_node.getNode(), ROUTING_PROTOCOL_OSPFv2);
+
+ if( interface==-2 ) invalidate( );
+
+#ifdef NDN_DEBUG_OSPF
+ if( interface==-1 ) printf( "Routing/interface costs\n" );
+#endif // NDN_DEBUG_OSPF
+
+#ifdef NDN_DEBUG_OSPF_NODES
+ printf( "-- Node %d (interface %d) --\n", _node.getNode()->nodeId, interface );
+#endif // NDN_DEBUG_OSPF_NODES
+
+ Ospfv2RoutingTableRow* rowPtr = (Ospfv2RoutingTableRow*)
+ BUFFER_GetData(&ospf->routingTable.buffer);
+
+ for (int i = 0; i < ospf->routingTable.numRows; i++)
+ {
+ NodeAddress destNodeId = Ipv4ToNodeId( rowPtr[i].destAddr );
+
+ if( destNodeId!=-1 ) update( destNodeId, rowPtr[i].metric, rowPtr[i].nextHop );
+ }
+
+#ifdef NDN_DUMP_FIB
+ if( interface==-1 ) dump( );
+#endif
+}
+
+void NdnFib::updateFibFromBGP( )
+{
+ BgpData* bgp=(BgpData*)_node.getNode()->appData.exteriorGatewayVar;
+
+ assert( bgp->ip_version == NETWORK_IPV4 );
+
+ invalidate( );
+
+ int i=0;
+ int numEntriesInAdjRibIn=BUFFER_GetCurrentSize( &( bgp->adjRibIn ) )
+ / sizeof(BgpRoutingInformationBase );
+
+ BgpRoutingInformationBase* adjRibInPtr=(BgpRoutingInformationBase*)
+ BUFFER_GetData( &( bgp->adjRibIn ) );
+
+ for( i=0; i < numEntriesInAdjRibIn; i++ )
+ {
+ assert( adjRibInPtr[i].nextHop.networkType == NETWORK_IPV4 );
+
+ NodeAddress destNodeId = Ipv4ToNodeId( GetIPv4Address(adjRibInPtr[i].destAddress.prefix) );
+
+ if( destNodeId!=-1 && adjRibInPtr[i].isValid != FALSE )
+ {
+ char destNodeStr[NDN_MAX_NAME_LENGTH];
+ memset(destNodeStr, 0, NDN_MAX_NAME_LENGTH);
+ sprintf(destNodeStr, "%d", destNodeId);
+
+ update( destNodeId,
+ adjRibInPtr[i].asPathList->pathSegmentLength / 2,
+ GetIPv4Address(adjRibInPtr[i].nextHop) );
+ }
+ }
+
+#ifdef NDN_DUMP_FIB
+ dump( );
+#endif
+}
+
+void NdnFib::updateFibFromIpRouting( )
+{
+ invalidate( );
+
+ for (int i = 0; i < _node.getNode()->partitionData->numNodes; i ++)
+ {
+ if( !_node.getNode()->networkData.networkVar->ndnEnabled ) continue;
+
+ NodeAddress destNode = _node.getNode()->partitionData->nodeData[i]->nodeId;
+ NodeAddress ipv4subnet = NodeIdToIpv4( destNode );
+
+ int interfaceIndex;
+ NodeAddress nextHopAddr;
+ NetworkGetInterfaceAndNextHopFromForwardingTable(
+ _node.getNode(), ipv4subnet, &interfaceIndex, &nextHopAddr );
+
+ if( interfaceIndex != NETWORK_UNREACHABLE )
+ {
+ update( destNode, interfaceIndex, 1, nextHopAddr );
+ }
+ }
+}
+
+
+
+void NdnFib::dump( )
+{
+ if( _node.getNode()->numberInterfaces==1 ) return; // do not dump FIB for `virtual' nodes
+
+ printf( "Node %s: FIB\n", _node.getPrefix().c_str() );
+ printf( " Dest prefix Interfaces(Costs) \n" );
+ printf( "+-------------+--------------------------------------+\n" );
+
+ for( FibRangeIterator fib=_fib.begin(); fib!=_fib.end(); fib++ )
+ {
+ dump( fib );
+ }
+}
+
+void NdnFib::dump( const FibIterator &fib )
+{
+ printf( " %8s ", fib->first.c_str() );
+ for( FibNexthopIterator nh=VALUE(fib).forwardingList.begin(); nh!=VALUE(fib).forwardingList.end(); nh++ )
+ {
+ if( nh!=VALUE(fib).forwardingList.begin() ) printf( "," );
+ printf( "i%d(%d)", nh->interfaceIndex, nh->cost );
+ }
+ printf( "\n" );
+}
+
+void NdnFib::resetProbing()
+{
+ for(FibRangeIterator fib = _fib.begin(); fib != _fib.end(); fib++)
+ VALUE(fib).needsProbing = true;
+}
+
+void NdnFib::updateInterfaceStatus( int interface, int status )
+{
+ for( FibRangeIterator fib = _fib.begin(); fib!=_fib.end(); fib++ )
+ {
+ VALUE(fib).updateStatus( interface, status );
+ }
+}
\ No newline at end of file
diff --git a/in-progress/ccnx-fib.h b/in-progress/ccnx-fib.h
new file mode 100644
index 0000000..9a1c3d6
--- /dev/null
+++ b/in-progress/ccnx-fib.h
@@ -0,0 +1,193 @@
+/*
+ * File: ndn_fib.h
+ * Author: cawka
+ *
+ * Created on December 15, 2010, 1:54 PM
+ */
+
+#ifndef NDN_FIB_H
+#define NDN_FIB_H
+
+#include "hash_helper.h"
+#include <clock.h>
+#include <main.h>
+
+class Ndn;
+
+const int NDN_FIB_GREEN = 1;
+const int NDN_FIB_YELLOW = 2;
+const int NDN_FIB_RED = 3;
+
+//structure for Fib outgoing interface
+struct FibNexthop
+{
+ int interfaceIndex; //interface index of the node
+ NodeAddress nextHop; //next-hop
+ int cost; //routing protocol cost to route an interest via this interface
+ int packetCount; //record the number of packets forwarded using this interface
+
+ clocktype srtt; //smoothed round-trip time
+ clocktype rttvar; //round-trip time variation
+
+ int status; // Status of the next hop:
+ // - #NDN_FIB_GREEN
+ // - #NDN_FIB_YELLOW
+ // - #NDN_FIB_RED
+
+ bool operator==( int interface ) const { return interfaceIndex==interface; }
+ FibNexthop( ) {}
+ FibNexthop( int _interface, int _nextHop, int _cost )
+ : interfaceIndex(_interface), nextHop(_nextHop), cost(_cost)
+ , packetCount(1), srtt(0), rttvar(0), status(NDN_FIB_YELLOW) { }
+};
+
+typedef list<FibNexthop>::iterator FibNexthopIterator;
+typedef list<FibNexthop>::const_iterator FibNexthopConstIterator;
+
+//structure for FIB table entry
+struct FibEntry
+{
+ list<FibNexthop> forwardingList;
+ clocktype sto; //retransmission time out
+
+ bool needsProbing; //set to true when probing timer goes out
+
+ FibEntry( ) : sto(0), needsProbing(false) { }
+
+ // Find nexthop record
+ inline FibNexthopIterator findNexthop( int interfaceIndex );
+ bool isValid( const FibNexthopIterator &nh )
+ { return nh!=forwardingList.end(); }
+
+ // Compute and update RTO value for Fib Entry (RFC 2988)
+ // (for now we pick the maximum RTO of all forwardings)
+ void updateSto( );
+
+ // Update status of FIB next hop
+ inline void updateStatus( int interface, int status );
+};
+
+typedef string_key_hash_t<FibEntry>::point_iterator FibIterator;
+typedef string_key_hash_t<FibEntry>::iterator FibRangeIterator;
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+// Class implementing FIB functionality
+class NdnFib
+{
+public:
+ NdnFib( Ndn &node );
+ virtual ~NdnFib( );
+
+ // Invalidate entries in FIB
+ // Will leave FIB records in hash, but assign metric=NETWORK_UNREACHABLE
+ void invalidate( );
+
+ //Find corresponding FIB entry for the given content name
+ //Longest match is performed
+ FibIterator lookup( const string &name );
+ bool isValid( const FibIterator &it ) { return it!=_fib.end(); }
+
+ /**
+ * Update FIB entry
+ * If the entry exists, metric will be updated. Otherwise, new entry will be created
+ *
+ * Entries in FIB never deleted. They can be invalidated with metric==NETWORK_UNREACHABLE
+ *
+ * @param name Prefix
+ * @param interfaceIndex Forwarding interface
+ * @param metric Routing metric
+ * @param nextHop Nexthop node address (IPv4)
+ * @return true if a new entry created, false otherwise
+ */
+ bool update( const string &name, int interfaceIndex, int metric, NodeAddress nextHop );
+ bool update( NodeAddress nodeId, int interfaceIndex, int metric, NodeAddress nextHop );
+ bool update( NodeAddress nodeId, int metric, NodeAddress nextHop );
+
+ // Update Fib from OSPF routing table (through a hack in OSPF algorithm)
+ void updateFibFromOSPFv2( int interface );
+
+ // Update Fib from BGP routing table (using info from RibIn)
+ void updateFibFromBGP( );
+
+ // Update Fib from IP routing table
+ void updateFibFromIpRouting( );
+
+ // Update the status for all FIB records for the specified interface
+ void updateInterfaceStatus( int interface, int status );
+
+ void dump( );
+ void dump( const FibIterator &fib );
+
+ void resetProbing(); //reset needsProbing field for every FibEntry
+private:
+
+private:
+ Ndn &_node;
+
+ string_key_hash_t<FibEntry> _fib;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+class NdnFibNexthopSorter
+{
+public:
+ bool operator()( const FibNexthop &first, const FibNexthop &second );
+};
+
+FibNexthopIterator FibEntry::findNexthop( int interfaceIndex )
+{
+ return find( forwardingList.begin( ),
+ forwardingList.end( ),
+ interfaceIndex );
+}
+
+//inline FibNexthopIterator FibEntry::findBestNexthop( int bestNum, int excludeInterface )
+//{
+// // First adjust number of available interfaces (to make sure we have correct ranking function)
+// int num_valid_interfaces = forwardingList.size();
+// FibNexthopIterator nh;
+// for( nh=forwardingList.begin(); nh!=forwardingList.end(); nh++ )
+// {
+// if( nh->interfaceIndex==excludeInterface ) num_valid_interfaces--;
+// }
+//
+// if( num_valid_interfaces==0 ) return forwardingList.end();
+//
+// bestNum = bestNum % num_valid_interfaces;
+// int i=0;
+// for( nh=forwardingList.begin(); nh!=forwardingList.end(); nh++ ) // skip bestNum % size() FIB records
+// {
+// if( nh->interfaceIndex==excludeInterface ) continue;
+// if( i==bestNum ) break;
+//
+// i++;
+// }
+//
+// if( nh!=forwardingList.end() )
+// {
+// assert( nh->interfaceIndex!=excludeInterface );
+//// printf( "%d best => i%d\n", bestNum, nh->interfaceIndex );
+// }
+//// else
+//// {
+//// printf( "No other hops available\n" );
+//// }
+//
+//
+// return nh;
+//}
+
+void FibEntry::updateStatus( int interface, int status )
+{
+ FibNexthopIterator nh = findNexthop( interface );
+ if( isValid(nh) )
+ {
+ nh->status = status;
+ }
+}
+
+#endif /* NDN_FIB_H */
diff --git a/in-progress/ccnx-pit.cpp b/in-progress/ccnx-pit.cpp
new file mode 100644
index 0000000..5d10b90
--- /dev/null
+++ b/in-progress/ccnx-pit.cpp
@@ -0,0 +1,243 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+//
+// Copyright (c) 2010,2011 UCLA
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation;
+//
+// This program 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 this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author:
+//
+
+#include "ccnx-pit.h"
+#include <algorithm>
+
+CcnxPit::CcnxPit( Ccnx &node )
+: _node(node)
+{
+};
+
+CcnxPit::~CcnxPit( ) { }
+
+//Find corresponding CS entry for the given content name
+PitIterator CcnxPit::lookup( const string &prefix )
+{
+ QNThreadLock lock( &_pitMutex );
+
+ PitIterator entry=_pit.find( prefix );
+ return entry;
+}
+
+// add new PIT entry
+bool CcnxPit::add( const string &name, const PitIncomingInterest &interest )
+{
+ QNThreadLock lock( &_pitMutex );
+
+ PitEntry *entry=NULL;
+
+ PitIterator existent_entry = _pit.find( name );
+ if( isValid(existent_entry) )
+ {
+ if( VALUE(existent_entry).timerExpired )
+ {
+ _node.fillAvailableInterfacesInPitEntry( VALUE(existent_entry) );
+ }
+
+ add( VALUE(existent_entry), interest );
+ }
+ else
+ {
+ PitEntry &entry = _pit[ name ];
+ entry.contentName = name;
+
+ _node.fillAvailableInterfacesInPitEntry( entry );
+
+ add( entry, interest );
+ }
+}
+
+// Remove expired records from PIT
+void CcnxPit::cleanExpired( clocktype time )
+{
+ QNThreadLock lock( &_pitMutex );
+
+ while( !_pitExpirationList.empty() )
+ {
+ PitExpirationIterator entry = _pitExpirationList.begin( );
+
+ if( VALUE(entry)->expireTime <= time )
+ {
+ deleteIncomingInterest( *(KEY(entry)), VALUE(entry)->interfaceIndex );
+
+ // delete entry if all incoming interests expired
+ if( KEY(entry)->incomingInterests.size()==0 )
+ {
+ _pit.erase( KEY(entry)->contentName );
+ }
+ }
+ else
+ break;
+ }
+}
+
+//delete PIT entry
+void CcnxPit::erase( const string &name )
+{
+ // should not call `lookup' method !!!
+
+ QNThreadLock lock( &_pitMutex );
+
+ PitIterator pe = _pit.find( name );
+
+ if( !isValid(pe) ) return;
+
+ if( VALUE(pe).timerMsg ) MESSAGE_CancelSelfMsg( _node.getNode(), VALUE(pe).timerMsg );
+
+ PitIncomingIterator it = VALUE(pe).incomingInterests.begin();
+ while( it!=VALUE(pe).incomingInterests.end() )
+ {
+ deleteIncomingInterest( VALUE(pe), it );
+
+ it = VALUE(pe).incomingInterests.begin();
+ }
+
+ resetPendingState( VALUE(pe) );
+
+ _pit.erase( name );
+}
+
+//delete incoming interest from PIT entry
+//return 0 if interest does not exist, 1 otherwise
+bool CcnxPit::deleteIncomingInterest( PitEntry &pe, int interfaceIndex )
+{
+ // should not lock thread !!! Otherwise there will be a deadlock
+ if( pe.incomingInterests.size()==0 ) return false; //nothing to delete. Can happen when duplicate data arrives to the node
+
+ PitIncomingIterator it = findIncoming( pe, interfaceIndex );
+
+ if( !isValid(pe, it) ) return false;
+
+ deleteIncomingInterest( pe, it );
+
+ return true;
+}
+
+void CcnxPit::deleteAllIncomingInterests( PitEntry &pe )
+{
+ PitIncomingIterator it = pe.incomingInterests.begin();
+ while( it!=pe.incomingInterests.end() )
+ {
+ deleteIncomingInterest( pe, it );
+
+ it = pe.incomingInterests.begin();
+ }
+}
+
+void CcnxPit::deleteIncomingInterest( PitEntry &pe, PitIncomingIterator it )
+{
+ assert( KEY(it->expirationPosition)==&pe );
+ assert( VALUE(it->expirationPosition)->interfaceIndex==it->interfaceIndex );
+
+ _pitExpirationList.erase( it->expirationPosition );
+ pe.incomingInterests.erase( it );
+}
+
+//add new incoming interest to PIT entry
+//returns false if interface already exists, true otherwise
+bool CcnxPit::add( PitEntry &pe, const PitIncomingInterest &interest )
+{
+ pe.availableInterfaces.remove( interest.interfaceIndex );
+
+ PitIncomingIterator it=findIncoming( pe, interest.interfaceIndex );
+
+ if( isValid(pe, it) )
+ {
+ //update expiration time
+ it->expireTime = interest.expireTime;
+ it->nonce = interest.nonce;
+
+ //move Interest to the end of the node's Interest list
+ _pitExpirationList.erase( it->expirationPosition );
+ _pitExpirationList.push_back( PitExpirationEntry(&pe,&(*it)) );
+
+ it->expirationPosition = --_pitExpirationList.end();
+ return false;
+ }
+
+ pe.incomingInterests.push_back( interest );
+ PitIncomingInterest *incoming = &pe.incomingInterests.back();
+
+ //Add to the end of the node's Interest list
+ _pitExpirationList.push_back( PitExpirationEntry(&pe,incoming) );
+ incoming->expirationPosition = -- _pitExpirationList.end();
+
+ return true;
+}
+
+//add new outgoing interest to PIT entry
+//returns false interface limit reached or interest exists and is still marked as outstanding (nonce will not be changed)
+// true otherwise
+int CcnxPit::add( PitEntry &pe, const PitOutgoingInterest &interest )
+{
+ if( _node.isRateLimit && _bucketsPerInterface[interest.interfaceIndex]+1.0 >= maxBucketsPerInterface[interest.interfaceIndex] )
+ {
+// printf( "DEBUG: bucket overflow. Should not forward anything to interface %d\n", interest.interfaceIndex );
+ return false;
+ }
+
+ _bucketsPerInterface[interest.interfaceIndex] = _bucketsPerInterface[interest.interfaceIndex] + 1.0;
+ pe.availableInterfaces.remove( interest.interfaceIndex );
+
+ PitOutgoingIterator it = findOutgoing(pe, interest.interfaceIndex);
+ if( isValid(pe, it) )
+ {
+ if( it->outstanding ) return false;
+
+ it->retxNum ++;
+ it->nonce = interest.nonce;
+ it->outstanding = true;
+ it->waitingInVain = false;
+ }
+ else
+ {
+ //add to the head of the list
+ pe.outgoingInterests.push_front( interest );
+ }
+
+ return true;
+}
+
+void CcnxPit::resetPendingState( PitEntry &pe )
+{
+ for( PitOutgoingIterator it = pe.outgoingInterests.begin();
+ it != pe.outgoingInterests.end();
+ it++ )
+ {
+ it->outstanding = false;
+ }
+}
+
+void CcnxPit::leakBuckets( )
+{
+ for( PitBucketIterator it=_bucketsPerInterface.begin();
+ it != _bucketsPerInterface.end();
+ it++ )
+ {
+ it->second = max( 0.0, it->second - leakSize[it->first] );
+ }
+}
+
+void CcnxPit::leakBucket( int interface, int amount )
+{
+ _bucketsPerInterface[interface] =
+ max( 0.0, _bucketsPerInterface[interface] - amount );
+}
diff --git a/in-progress/ccnx-pit.h b/in-progress/ccnx-pit.h
new file mode 100644
index 0000000..83fad09
--- /dev/null
+++ b/in-progress/ccnx-pit.h
@@ -0,0 +1,276 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+//
+// Copyright (c) 2010,2011 UCLA
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation;
+//
+// This program 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 this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Author:
+//
+
+#ifndef CCNX_PIT_H
+#define CCNX_PIT_H
+
+#include "ns3/nstime.h"
+#include "hash-helper.h"
+#include <list>
+
+namespace ns3 {
+
+class Ccnx;
+class PitEntry;
+class PitIncomingInterest;
+typedef pair<PitEntry*,PitIncomingInterest*> PitExpirationEntry;
+typedef list<PitExpirationEntry>::iterator PitExpirationIterator;
+
+struct PitIncomingInterest
+{
+ int interfaceIndex; // interface index of the incoming Interest
+ Time expireTime; // life time of the incoming Interest
+ int nonce; // nonce of the last received incoming Interest on this interface
+
+ PitExpirationIterator expirationPosition;
+
+public:
+PitIncomingInterest( int _interface, clocktype _expire, int _nonce )
+: interfaceIndex(_interface)
+, expireTime(_expire)
+ , nonce(_nonce)
+ { };
+
+ bool operator==( const PitIncomingInterest &dst ) { return interfaceIndex==dst.interfaceIndex; }
+ bool operator==( int interface ) { return interfaceIndex==interface; }
+};
+
+struct PitOutgoingInterest
+{
+ int interfaceIndex;
+ clocktype sendTime; //time when the first outgoing interest is sent
+ int retxNum; //number of retransmission
+ int nonce; //nonce of the outgoing Interest
+ bool outstanding; //flag to indicate that this interest is currently pending
+ bool waitingInVain; //when flag is set, we do not expect data for this interest, only a small hope that it will happen
+
+public:
+PitOutgoingInterest( int interface, clocktype time, int nonce )
+: interfaceIndex(interface)
+, sendTime( time )
+ , retxNum( 0 )
+ , nonce( nonce )
+ , outstanding( true )
+ , waitingInVain( false )
+ { };
+
+ bool operator==( const PitIncomingInterest &dst ) { return interfaceIndex==dst.interfaceIndex; }
+ bool operator==( int interface ) { return interfaceIndex==interface; }
+};
+
+
+//structure for PIT entry
+struct PitEntry
+{
+ string contentName;
+ list<PitIncomingInterest> incomingInterests;
+ list<PitOutgoingInterest> outgoingInterests;
+
+ bool timerExpired;
+ int counterExpirations; //whether timer is expired (+ number of times timer expired)
+
+ /**
+ * This variable provides a list of interfaces that will be tried to propagate interest
+ *
+ * It should be initialized with all available interfaces upon reception of first or
+ * any retransmitted (i.e., after STO expired), but not duplicate interests
+ *
+ * Reaction to duplicate interests depends on strategy.
+ *
+ * In case of flooding, this variable should always be empty (it is filled initially with
+ * all avaialble interfaces and then immediately emptied by interest flooding)
+ *
+ * In case of routing strategies, this list will guide (and limit) the local recovery process
+ */
+ list<int> availableInterfaces;
+
+ Message *timerMsg; //the timer message, used to cancel message if data is received
+
+ // Changing PIT removal policy. From now on it will be deleted only when all outgoing
+ // interests are satisfied
+ //
+ // bool dontDeleteOnFirstData; //don't delete when first data packet comes
+ // //(PIT will be deleted only upon timeout or reception data
+ // //packets or prunes for all outgoing interests)
+
+public:
+PitEntry()
+: timerExpired( false )
+, counterExpirations( 0 )
+ , timerMsg( NULL )
+ { }
+
+ inline void fillAvailableInterfacesFromFIB( const FibEntry &fe );
+
+ // Find best candidate, skipping `skip' first candidates (modulo availableInterfaces.size())
+ // !!! assert( availableInterfaces.size()>0 ) !!!
+ inline int findBestCandidate( int skip = 0 );
+
+ // Get number of outgoing interests that we're expecting data from
+ inline size_t numberOfPromisingInterests( ) const;
+};
+
+typedef string_key_hash_t<PitEntry>::point_iterator PitIterator;
+typedef string_key_hash_t<PitEntry>::iterator PitRangeIterator;
+
+typedef list<PitIncomingInterest>::iterator PitIncomingIterator;
+typedef list<PitOutgoingInterest>::iterator PitOutgoingIterator;
+typedef list<PitOutgoingInterest>::const_iterator PitOutgoingConstIterator;
+
+typedef map<int,int> PitCounter;
+typedef map<int,int>::iterator PitCounterIterator;
+
+typedef map<int,double> PitBucket;
+typedef map<int,double>::iterator PitBucketIterator;
+
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+// class implementing Pending Interests Table
+class CcnxPit
+{
+ public:
+ /**
+ * PIT constructor
+ */
+ CcnxPit( Ccnx &node );
+ virtual ~CcnxPit( );
+
+ //Find corresponding PIT entry for the given content name
+ PitIterator lookup( const string &prefix );
+ bool isValid( const PitIterator &it ) { return it!=_pit.end(); }
+
+ inline PitIncomingIterator findIncoming( PitEntry &pe, int interfaceIndex );
+ inline bool isValid( PitEntry &pe, PitIncomingIterator it );
+ inline PitOutgoingIterator findOutgoing( PitEntry &pe, int interfaceIndex );
+ inline bool isValid( PitEntry &pe, PitOutgoingIterator it );
+
+ // Add a new PIT entry and a correspondent new incoming interest
+ bool add( const string &contentName, const PitIncomingInterest &interest );
+
+ // Add a new outgoing interest
+ int add( PitEntry &pe, const PitOutgoingInterest &interest );
+
+ // remove a PIT entry
+ void erase( const string &contentName );
+
+ // inline bool InterestAlreadyForwarded( PitEntry &pe, int interfaceIndex );
+
+ // Remove expired records from PIT
+ void cleanExpired( clocktype time );
+
+ // Dump content store entries
+ void dump( );
+
+ // Reset pending state in outgoing interests
+ void resetPendingState( PitEntry &pe );
+
+ // // Check if there are any interfaces that we haven't sent data to yet
+ // bool areFreeInterfaces( PitEntry &pe, int interface );
+
+ // Periodically generate pre-calculated number of tokens (leak buckets)
+ void leakBuckets( );
+
+ // Selectively leak a bucket
+ void leakBucket( int interface, int amount );
+
+ // Delete incoming interest for the interface
+ bool deleteIncomingInterest( PitEntry &pe, int interfaceIndex );
+
+ // Remove all incoming interests
+ void deleteAllIncomingInterests( PitEntry &pe );
+
+ public:
+ PitBucket maxBucketsPerInterface; // maximum number of buckets. Automatically computed based on link capacity
+ // averaging over 1 second (bandwidth * 1second)
+ PitBucket leakSize; // size of a periodic bucket leak
+
+ private:
+ bool add( PitEntry &pe, const PitIncomingInterest &interest );
+ void deleteIncomingInterest( PitEntry &pe, PitIncomingIterator it );
+
+ private:
+ Ccnx &_node;
+
+ string_key_hash_t<PitEntry> _pit;
+
+ list<PitExpirationEntry> _pitExpirationList; //list of incoming Interests sorted by expiration time
+
+ PitBucket _bucketsPerInterface; // pending interface counter per interface
+
+ QNThreadMutex _pitMutex; // just to make sure
+};
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+PitIncomingIterator CcnxPit::findIncoming( PitEntry &pe, int interfaceIndex )
+{
+ return find( pe.incomingInterests.begin( ),
+ pe.incomingInterests.end( ),
+ interfaceIndex );
+}
+
+PitOutgoingIterator CcnxPit::findOutgoing( PitEntry &pe, int interfaceIndex )
+{
+ return find( pe.outgoingInterests.begin( ),
+ pe.outgoingInterests.end( ),
+ interfaceIndex );
+}
+
+bool CcnxPit::isValid( PitEntry &pe, PitIncomingIterator it )
+{
+ return it!=pe.incomingInterests.end( );
+}
+
+bool CcnxPit::isValid( PitEntry &pe, PitOutgoingIterator it )
+{
+ return it!=pe.outgoingInterests.end( );
+}
+
+int PitEntry::findBestCandidate( int skip/* = 0*/ )
+{
+ assert( availableInterfaces.size()>0 );
+
+ skip = skip % availableInterfaces.size();
+ list<int>::iterator candidate = availableInterfaces.begin( );
+ while( skip>0 /* && candidate!=availableInterfaces.end() */ ) { skip--; candidate++; }
+
+ return *candidate;
+}
+
+size_t PitEntry::numberOfPromisingInterests( ) const
+{
+ size_t count = 0;
+
+ for( PitOutgoingConstIterator i = outgoingInterests.begin();
+ i!=outgoingInterests.end();
+ i++ )
+ {
+ if( !i->waitingInVain ) count++;
+ }
+
+ return count;
+}
+
+} // namespace ns3
+
+#endif /* CCNX_PIT_H */
diff --git a/in-progress/ccnx-rit.cpp b/in-progress/ccnx-rit.cpp
new file mode 100644
index 0000000..b84f9d0
--- /dev/null
+++ b/in-progress/ccnx-rit.cpp
@@ -0,0 +1,64 @@
+/*
+ * File: ndn_rit.cpp
+ * Author: cawka
+ *
+ * Created on December 15, 2010, 2:02 PM
+ */
+
+#include "ndn_rit.h"
+
+NdnRit::NdnRit( ) { }
+
+NdnRit::~NdnRit( ) { }
+
+
+//find corresponding RIT entry for the given nonce
+RitIterator NdnRit::lookup( int nonce )
+{
+ QNThreadLock lock( &_ritMutex );
+
+ RitIterator entry=_rit.find( nonce );
+ return entry;
+}
+
+
+// add new RIT entry
+// returns false if entry already exists, otherwise returns true
+bool NdnRit::add( int nonce, clocktype expire )
+{
+ QNThreadLock lock( &_ritMutex );
+
+ RitIterator entry=_rit.find( nonce );
+ if( isValid(entry) ) return false;
+
+ RitEntry re;
+ re.nonce = nonce;
+ re.expireTime = expire;
+
+ _rit[ nonce ] = re;
+
+ _ritExpirationList.push_back( &(_rit[nonce]) );
+}
+
+
+void NdnRit::cleanExpired( clocktype time )
+{
+ QNThreadLock lock( &_ritMutex );
+
+ while( !_ritExpirationList.empty() )
+ {
+ RitEntry *head = _ritExpirationList.front( );
+
+ if( head->expireTime <= time )
+ {
+ //delete the head RIT entry
+ _rit.erase( head->nonce );
+ _ritExpirationList.pop_front( );
+ }
+ else
+ break;
+ }
+ //printf("Node %d: RIT entries\n", node->nodeId);
+ //PrintRitEntries(ndn->riList);
+}
+
diff --git a/in-progress/ccnx-rit.h b/in-progress/ccnx-rit.h
new file mode 100644
index 0000000..4a03bda
--- /dev/null
+++ b/in-progress/ccnx-rit.h
@@ -0,0 +1,52 @@
+/*
+ * File: ndn_rit.h
+ * Author: cawka
+ *
+ * Created on December 15, 2010, 2:02 PM
+ */
+
+#ifndef NDN_RIT_H
+#define NDN_RIT_H
+
+#include "hash_helper.h"
+#include <qualnet_mutex.h>
+#include <clock.h>
+#include <list>
+using namespace std;
+
+//recent interest
+struct RitEntry
+{
+ int nonce;
+ clocktype expireTime; //RIT entries will stay in the table for a while before being cleaned out
+};
+
+typedef int_key_hash_t<RitEntry>::point_iterator RitIterator;
+typedef int_key_hash_t<RitEntry>::iterator RitRangeIterator;
+
+class NdnRit
+{
+public:
+ NdnRit( );
+ virtual ~NdnRit( );
+
+ //Find corresponding RIT entry for the given content name
+ RitIterator lookup( int nonce );
+ bool isValid( const RitIterator &it ) { return it!=_rit.end(); }
+
+ //add new RIT entry
+ bool add( int nonce, clocktype expireTime );
+
+ // Delete expired records
+ void cleanExpired( clocktype time );
+
+private:
+ int_key_hash_t<RitEntry> _rit;
+
+ list<RitEntry*> _ritExpirationList;
+
+ QNThreadMutex _ritMutex;
+};
+
+#endif /* NdnRit_H */
+