Merge remote-tracking branch 'git.irl/master'
diff --git a/model/sync-app-data-fetch.cc b/ccnx/sync-app-data-fetch.cc
similarity index 100%
rename from model/sync-app-data-fetch.cc
rename to ccnx/sync-app-data-fetch.cc
diff --git a/model/sync-app-data-fetch.h b/ccnx/sync-app-data-fetch.h
similarity index 100%
rename from model/sync-app-data-fetch.h
rename to ccnx/sync-app-data-fetch.h
diff --git a/model/sync-app-data-publish.cc b/ccnx/sync-app-data-publish.cc
similarity index 100%
rename from model/sync-app-data-publish.cc
rename to ccnx/sync-app-data-publish.cc
diff --git a/model/sync-app-data-publish.h b/ccnx/sync-app-data-publish.h
similarity index 100%
rename from model/sync-app-data-publish.h
rename to ccnx/sync-app-data-publish.h
diff --git a/model/sync-app-socket-c.cc b/ccnx/sync-app-socket-c.cc
similarity index 100%
rename from model/sync-app-socket-c.cc
rename to ccnx/sync-app-socket-c.cc
diff --git a/model/sync-app-socket-c.h b/ccnx/sync-app-socket-c.h
similarity index 100%
rename from model/sync-app-socket-c.h
rename to ccnx/sync-app-socket-c.h
diff --git a/model/sync-app-socket.cc b/ccnx/sync-app-socket.cc
similarity index 100%
rename from model/sync-app-socket.cc
rename to ccnx/sync-app-socket.cc
diff --git a/model/sync-app-socket.h b/ccnx/sync-app-socket.h
similarity index 100%
rename from model/sync-app-socket.h
rename to ccnx/sync-app-socket.h
diff --git a/model/sync-ccnx-wrapper.cc b/ccnx/sync-ccnx-wrapper.cc
similarity index 100%
rename from model/sync-ccnx-wrapper.cc
rename to ccnx/sync-ccnx-wrapper.cc
diff --git a/model/sync-ccnx-wrapper.h b/ccnx/sync-ccnx-wrapper.h
similarity index 100%
rename from model/sync-ccnx-wrapper.h
rename to ccnx/sync-ccnx-wrapper.h
diff --git a/model/sync-log.cc b/ccnx/sync-log.cc
similarity index 100%
rename from model/sync-log.cc
rename to ccnx/sync-log.cc
diff --git a/model/sync-log.h b/ccnx/sync-log.h
similarity index 100%
rename from model/sync-log.h
rename to ccnx/sync-log.h
diff --git a/model/sync-logic-event-container.h b/ccnx/sync-logic-event-container.h
similarity index 97%
rename from model/sync-logic-event-container.h
rename to ccnx/sync-logic-event-container.h
index 65c8ab2..ebab72a 100644
--- a/model/sync-logic-event-container.h
+++ b/ccnx/sync-logic-event-container.h
@@ -23,6 +23,8 @@
 #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>
 
@@ -40,8 +42,6 @@
 namespace Sync
 {
 
-typedef boost::function< void ( ) > Event;
-
 struct LogicEvent
 {
   LogicEvent (const boost::system_time &_time, Event _event, uint32_t _label)
diff --git a/model/sync-scheduler.cc b/ccnx/sync-scheduler.cc
similarity index 90%
rename from model/sync-scheduler.cc
rename to ccnx/sync-scheduler.cc
index 4f9e082..866f742 100644
--- a/model/sync-scheduler.cc
+++ b/ccnx/sync-scheduler.cc
@@ -107,26 +107,18 @@
   // cout << "Exited...\n";  
 }
 
-
 void
-Scheduler::schedule (const boost::system_time &abstime, Event event, uint32_t label)
+Scheduler::schedule (const TimeDuration &reltime, Event event, uint32_t label)
 {
   {
     lock_guard<mutex> lock (m_eventsMutex);
-    m_events.insert (LogicEvent (abstime, event, label));
+    m_events.insert (LogicEvent (boost::get_system_time () + reltime, event, label));
   }
   m_eventsCondition.notify_one ();
   m_thread.interrupt (); // interrupt sleep, if currently sleeping
 }
 
 void
-Scheduler::schedule (const boost::posix_time::time_duration &reltime, Event event, uint32_t label)
-{
-  // cout << reltime << endl;
-  schedule (boost::get_system_time () + reltime, event, label);
-}
-
-void
 Scheduler::cancel (uint32_t label)
 {
   {
diff --git a/model/sync-scheduler.h b/ccnx/sync-scheduler.h
similarity index 85%
rename from model/sync-scheduler.h
rename to ccnx/sync-scheduler.h
index 10ef210..c7ebe09 100644
--- a/model/sync-scheduler.h
+++ b/ccnx/sync-scheduler.h
@@ -28,6 +28,9 @@
 
 #include "sync-logic-event-container.h"
 
+#define TIME_SECONDS(number) boost::posix_time::seconds (number)
+typedef boost::posix_time::time_duration TimeDuration;
+
 namespace Sync {
 
 /**
@@ -49,22 +52,13 @@
   ~Scheduler ();
 
   /**
-   * @brief Schedule an event at absolute time 'abstime'
-   * @param abstime Absolute time
-   * @param event function to be called at the time
-   * @param label Label for the event
-   */
-  void
-  schedule (const boost::system_time &abstime, Event event, uint32_t label);
-
-  /**
    * @brief Schedule an event at relative time 'reltime'
    * @param reltime Relative time
    * @param event function to be called at the time
    * @param label Label for the event
    */
   void
-  schedule (const boost::posix_time::time_duration &reltime, Event event, uint32_t label); 
+  schedule (const TimeDuration &reltime, Event event, uint32_t label); 
 
   /**
    * @brief Cancel all events for the label
diff --git a/examples/sync-example.cc b/examples/sync-example.cc
index 57bf8b4..54f715f 100644
--- a/examples/sync-example.cc
+++ b/examples/sync-example.cc
@@ -1,23 +1,93 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 
-#include "ns3/core-module.h"
-#include "ns3/sync-helper.h"
+#include <ns3/core-module.h>
+#include <ns3/network-module.h>
+#include <ns3/NDNabstraction-module.h>
+#include <ns3/point-to-point-module.h>
+
+#include "sync-logic.h"
 
 using namespace ns3;
+using namespace Sync;
 
+NS_LOG_COMPONENT_DEFINE ("SyncExample");
+
+void OnUpdate (Ptr<Node> node, const std::string &prefix, const SeqNo &newSeq, const SeqNo &/*oldSeq*/)
+{
+  NS_LOG_LOGIC (Simulator::Now ().ToDouble (Time::S) <<"s\tNode: " << node->GetId () << ", prefix: " << prefix << ", seqNo: " << newSeq);
+}
+
+void OnRemove (Ptr<Node> node, const std::string &prefix)
+{
+  NS_LOG_LOGIC (Simulator::Now ().ToDouble (Time::S) <<"s\tNode: " << node->GetId () << ", prefix: "<< prefix);
+}
 
 int 
 main (int argc, char *argv[])
 {
-  bool verbose = true;
+  Config::SetDefault ("ns3::PointToPointNetDevice::DataRate", StringValue ("1Mbps"));
+  Config::SetDefault ("ns3::PointToPointChannel::Delay", StringValue ("10ms"));
+  Config::SetDefault ("ns3::DropTailQueue::MaxPackets", StringValue ("20"));
+  
+  Config::SetDefault ("ns3::CcnxFloodingStrategy::SmartFlooding", StringValue ("false"));
+
+  LogComponentEnable ("SyncExample", LOG_ALL);
+  
+  Time finishTime = Seconds (3.0); 
 
   CommandLine cmd;
-  cmd.AddValue ("verbose", "Tell application to log if true", verbose);
+  cmd.AddValue ("finish", "Finish time", finishTime);
+  cmd.Parse (argc, argv);
 
-  cmd.Parse (argc,argv);
+  // Creating nodes
+  NodeContainer nodes;
+  nodes.Create (3);
 
-  /* ... */
+  // Connecting nodes using two links
+  PointToPointHelper p2p;
+  p2p.Install (nodes.Get (0), nodes.Get (1));
+  p2p.Install (nodes.Get (1), nodes.Get (2));
 
+  Names::Add ("0", nodes.Get (0));
+  Names::Add ("1", nodes.Get (1));
+  Names::Add ("2", nodes.Get (2));
+  
+  // Install CCNx stack on all nodes
+  NS_LOG_INFO ("Installing CCNx stack");
+  CcnxStackHelper ccnxHelper;
+  ccnxHelper.SetForwardingStrategy ("ns3::CcnxFloodingStrategy");
+  ccnxHelper.SetDefaultRoutes (false);
+  ccnxHelper.InstallAll ();
+
+  ccnxHelper.AddRoute ("0", "/sync", 0, 0);
+  ccnxHelper.AddRoute ("1", "/sync", 0, 0);
+  ccnxHelper.AddRoute ("1", "/sync", 1, 0);
+  ccnxHelper.AddRoute ("2", "/sync", 0, 0);
+
+  ApplicationContainer apps;
+  Ptr<Application> app;
+  app = Create<SyncLogic> ("/sync",
+                           boost::bind (OnUpdate, nodes.Get (0), _1, _2, _3),
+                           boost::bind (OnRemove, nodes.Get (0), _1));
+
+  nodes.Get (0)->AddApplication (app);
+  apps.Add (app);
+
+  app = Create<SyncLogic> ("/sync",
+                           boost::bind (OnUpdate, nodes.Get (1), _1, _2, _3),
+                           boost::bind (OnRemove, nodes.Get (1), _1));
+
+  nodes.Get (1)->AddApplication (app);
+  apps.Add (app);
+
+  // one data
+  Simulator::ScheduleWithContext (0, Seconds (0.5), &SyncLogic::addLocalNames, DynamicCast<SyncLogic> (apps.Get (0)), "/0", 1, 1);
+
+  // two producers at the same time
+  Simulator::ScheduleWithContext (0, Seconds (1.001), &SyncLogic::addLocalNames, DynamicCast<SyncLogic> (apps.Get (0)), "/0", 1, 2);
+  Simulator::ScheduleWithContext (1, Seconds (1.001), &SyncLogic::addLocalNames, DynamicCast<SyncLogic> (apps.Get (1)), "/1", 1, 2);
+  
+  Simulator::Stop (finishTime);
   Simulator::Run ();
   Simulator::Destroy ();
   return 0;
diff --git a/log4cxx.properties b/log4cxx.properties
index 70f885a..23ff104 100644
--- a/log4cxx.properties
+++ b/log4cxx.properties
@@ -11,10 +11,10 @@
 #log4j.appender.A1.layout.ConversionPattern=%d{hh:mm:ss,SSS} %-14t %-14c  %m%n
 log4j.appender.A1.layout.ConversionPattern=%d{ss,SSS}  %-12c  %m%n
 
-log4j.logger.SyncLogic = TRACE
+log4j.logger.SyncLogic = DEBUG
 #log4j.logger.SyncInterestTable = TRACE
-# log4j.logger.AppDataFetch = TRACE
-# log4j.logger.Test = TRACE
+#log4j.logger.AppDataFetch = TRACE
+log4j.logger.Test = TRACE
 #log4j.logger.bgpparser=TRACE
 #log4j.logger.bgpparser.AttributeType=ERROR
 #log4j.logger.bgpparser.MRTCommonHeader=ERROR
diff --git a/model/sync-event.h b/model/sync-event.h
new file mode 100644
index 0000000..7808947
--- /dev/null
+++ b/model/sync-event.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 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: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ *         Chaoyi Bian <bcy@pku.edu.cn>
+ *	   Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#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/model/sync-interest-table.cc b/model/sync-interest-table.cc
index 7b9ed35..a9ed265 100644
--- a/model/sync-interest-table.cc
+++ b/model/sync-interest-table.cc
@@ -32,7 +32,7 @@
 
 SyncInterestTable::SyncInterestTable ()
 {
-  m_scheduler.schedule (posix_time::seconds (4),
+  m_scheduler.schedule (TIME_SECONDS (4),
                         bind (&SyncInterestTable::expireInterests, this),
                         0);
 }
@@ -113,7 +113,7 @@
 
   _LOG_DEBUG ("expireInterests (): expired " << count);
   
-  m_scheduler.schedule (posix_time::seconds (4),
+  m_scheduler.schedule (TIME_SECONDS (4),
                         bind (&SyncInterestTable::expireInterests, this),
                         0);
 }
diff --git a/model/sync-logic.cc b/model/sync-logic.cc
index 1e99e84..403138a 100644
--- a/model/sync-logic.cc
+++ b/model/sync-logic.cc
@@ -34,7 +34,9 @@
 using namespace std;
 using namespace boost;
 
-// INIT_LOGGER ("SyncLogic");
+#ifndef _STANDALONE
+INIT_LOGGER ("SyncLogic");
+#endif
 
 namespace Sync
 {
@@ -46,9 +48,14 @@
   , m_onUpdate (onUpdate)
   , m_onRemove (onRemove)
   , m_ccnxHandle(new CcnxWrapper())
+#ifndef NS3_MODULE
   , m_randomGenerator (static_cast<unsigned int> (std::time (0)))
   , m_rangeUniformRandom (m_randomGenerator, uniform_int<> (20,80))
+#else
+  , m_rangeUniformRandom (20,80)
+#endif
 {
+#ifdef _STANDALONE
 #ifdef _DEBUG
 #ifdef HAVE_LOG4CXX
   // _LOG_FUNCTION (syncPrefix);
@@ -57,13 +64,20 @@
   id ++;
 #endif
 #endif
+#endif
+
+  _LOG_DEBUG ("syncPrefix");
+  
+#ifndef NS3_MODULE
+  // In NS3 module these functions are moved to StartApplication method
   
   m_ccnxHandle->setInterestFilter (m_syncPrefix,
                                    bind (&SyncLogic::respondSyncInterest, this, _1));
 
-  m_scheduler.schedule (posix_time::seconds (0),
+  m_scheduler.schedule (TIME_SECONDS (0),
                         bind (&SyncLogic::sendSyncInterest, this),
                         REEXPRESSING_INTEREST);
+#endif
 }
 
 SyncLogic::~SyncLogic ()
@@ -74,6 +88,29 @@
   m_ccnxHandle.reset ();
 }
 
+#ifdef NS3_MODULE
+void
+SyncLogic::StartApplication ()
+{
+  m_ccnxHandle->SetNode (GetNode ());
+  m_ccnxHandle->StartApplication ();
+
+  m_ccnxHandle->setInterestFilter (m_syncPrefix,
+                                   bind (&SyncLogic::respondSyncInterest, this, _1));
+
+  m_scheduler.schedule (TIME_SECONDS (0),
+                        bind (&SyncLogic::sendSyncInterest, this),
+                        REEXPRESSING_INTEREST);
+}
+
+void
+SyncLogic::StopApplication ()
+{
+  m_ccnxHandle->StopApplication ();
+}
+#endif
+
+
 void
 SyncLogic::respondSyncInterest (const string &interest)
 {
@@ -113,7 +150,7 @@
                                  m_syncResponseFreshness);
       if (m_outstandingInterest == interestName)
         {
-          m_scheduler.schedule (posix_time::seconds (0),
+          m_scheduler.schedule (TIME_SECONDS (0),
                                 bind (&SyncLogic::sendSyncInterest, this),
                                 REEXPRESSING_INTEREST);
         }
@@ -154,12 +191,13 @@
     //   }
 
     m_syncInterestTable.remove (interestName);
+    _LOG_DEBUG (">> D" << interestName);
     m_ccnxHandle->publishData (interestName,
                                lexical_cast<string> (*stateDiff),
                                m_syncResponseFreshness);
     if (m_outstandingInterest == interestName)
       {
-        m_scheduler.schedule (posix_time::seconds (0),
+        m_scheduler.schedule (TIME_SECONDS (0),
                               bind (&SyncLogic::sendSyncInterest, this),
                               REEXPRESSING_INTEREST);
       }
@@ -168,7 +206,16 @@
 
   if (!timedProcessing)
     {
-      m_scheduler.schedule (posix_time::milliseconds (m_rangeUniformRandom ()) /*from 20 to 100ms*/,
+      uint32_t waitDelay =
+#ifndef NS3_MODULE
+        m_rangeUniformRandom ()
+#else
+        m_rangeUniformRandom.GetValue ()
+#endif
+        ;
+      
+      _LOG_DEBUG ("Digest is not in the log. Schedule processing after small delay: " << waitDelay << "ms");
+      m_scheduler.schedule (TIME_MILLISECONDS (waitDelay) /*from 20 to 100ms*/,
                             bind (&SyncLogic::processSyncInterest, this, digest, interestName, true),
                             DELAYED_INTEREST_PROCESSING);
       
@@ -184,7 +231,7 @@
 
       if (m_outstandingInterest == interestName)
         {
-          m_scheduler.schedule (posix_time::seconds (0),
+          m_scheduler.schedule (TIME_SECONDS (0),
                                 bind (&SyncLogic::sendSyncInterest, this),
                                 REEXPRESSING_INTEREST);
         }
@@ -200,12 +247,15 @@
   try
     {
       recursive_mutex::scoped_lock lock (m_stateMutex);
-      
+
       string last = name.substr(name.find_last_of("/") + 1);
       istringstream ss (dataBuffer);
 
+      m_syncInterestTable.remove (name); // just in case, remove both interests from our interest table. No reason to keep them there
       if (last == "state")
         {
+          m_syncInterestTable.remove (name.substr(0, name.find_last_of("/")));
+          
           FullState full;
           ss >> full;
           BOOST_FOREACH (LeafConstPtr leaf, full.getLeaves()) // order doesn't matter
@@ -276,7 +326,7 @@
   // if state has changed, then it is safe to express a new interest
   if (diffLog->getLeaves ().size () > 0)
     {
-      m_scheduler.schedule (posix_time::seconds (0),
+      m_scheduler.schedule (TIME_SECONDS (0),
                             bind (&SyncLogic::sendSyncInterest, this),
                             REEXPRESSING_INTEREST);
     }
@@ -286,7 +336,7 @@
       // Otherwise we will get immediate reply from the local daemon and there will be 100% utilization
       m_scheduler.cancel (REEXPRESSING_INTEREST);
       // m_scheduler.schedule (posix_time::seconds (0),
-      m_scheduler.schedule (posix_time::seconds (m_syncResponseFreshness) + posix_time::milliseconds (1),
+      m_scheduler.schedule (TIME_SECONDS (m_syncResponseFreshness) + TIME_MILLISECONDS (1),
                             bind (&SyncLogic::sendSyncInterest, this),
                             REEXPRESSING_INTEREST);
     }
@@ -318,7 +368,7 @@
         {
           _LOG_DEBUG ("Have satisfied our own interest. Scheduling interest reexpression");
           // we need to reexpress interest only if we satisfied our own interest
-          m_scheduler.schedule (posix_time::milliseconds (0),
+          m_scheduler.schedule (TIME_SECONDS (0),
                                 bind (&SyncLogic::sendSyncInterest, this),
                                 REEXPRESSING_INTEREST);
         }
@@ -401,7 +451,7 @@
                               bind (&SyncLogic::processSyncData, this, _1, _2));
 
   m_scheduler.cancel (REEXPRESSING_INTEREST);
-  m_scheduler.schedule (posix_time::seconds (4),
+  m_scheduler.schedule (TIME_SECONDS (4),
                         bind (&SyncLogic::sendSyncInterest, this),
                         REEXPRESSING_INTEREST);
 }
diff --git a/model/sync-logic.h b/model/sync-logic.h
index ad0a208..9734fad 100644
--- a/model/sync-logic.h
+++ b/model/sync-logic.h
@@ -43,6 +43,11 @@
 #endif
 #endif
 
+#ifdef NS3_MODULE
+#include <ns3/application.h>
+#include <ns3/random-variable.h>
+#endif
+
 namespace Sync {
 
 /**
@@ -51,6 +56,9 @@
  * interests and data)
  */
 class SyncLogic
+#ifdef NS3_MODULE
+  : public ns3::Application
+#endif
 {
 public:
   typedef boost::function< void ( const std::string &/*prefix*/, const SeqNo &/*newSeq*/, const SeqNo &/*oldSeq*/ ) > LogicUpdateCallback;
@@ -98,6 +106,12 @@
   Scheduler &
   getScheduler () { return m_scheduler; }
 #endif
+
+protected:
+#ifdef NS3_MODULE
+  virtual void StartApplication ();
+  virtual void StopApplication ();
+#endif
   
 private:
   void
@@ -130,8 +144,12 @@
 
   Scheduler m_scheduler;
 
+#ifndef NS3_MODULE
   boost::mt19937 m_randomGenerator;
   boost::variate_generator<boost::mt19937&, boost::uniform_int<> > m_rangeUniformRandom;
+#else
+  ns3::UniformVariable m_rangeUniformRandom;
+#endif
   
   static const int m_syncResponseFreshness = 2;
 
diff --git a/ns3/sync-ccnx-wrapper.cc b/ns3/sync-ccnx-wrapper.cc
new file mode 100644
index 0000000..9ef8cc4
--- /dev/null
+++ b/ns3/sync-ccnx-wrapper.cc
@@ -0,0 +1,258 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 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: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ *         Chaoyi Bian <bcy@pku.edu.cn>
+ *	   Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "sync-ccnx-wrapper.h"
+#include "sync-log.h"
+#include <boost/throw_exception.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/lambda/bind.hpp>
+
+namespace ll = boost::lambda;
+
+#include <ns3/ccnx-name-components.h>
+#include <ns3/ccnx-interest-header.h>
+#include <ns3/ccnx-content-object-header.h>
+#include <ns3/ccnx-face.h>
+#include <ns3/packet.h>
+#include <ns3/ccnx-fib.h>
+
+typedef boost::error_info<struct tag_errmsg, std::string> errmsg_info_str;
+typedef boost::error_info<struct tag_errmsg, int> errmsg_info_int;
+
+using namespace std;
+using namespace boost;
+using namespace ns3;
+
+INIT_LOGGER ("CcnxWrapper");
+
+namespace Sync {
+
+CcnxWrapper::CcnxWrapper()
+  : m_rand (0, std::numeric_limits<uint32_t>::max ())
+{
+}
+
+CcnxWrapper::~CcnxWrapper()
+{
+}
+
+void
+CcnxWrapper::StartApplication ()
+{
+  CcnxApp::StartApplication ();
+}
+
+void
+CcnxWrapper::StopApplication ()
+{
+  CcnxApp::StopApplication ();
+}
+
+int
+CcnxWrapper::publishData (const string &dataName, const string &dataBuffer, int freshness)
+{
+  // NS_LOG_INFO ("Requesting Interest: \n" << interestHeader);
+  _LOG_INFO ("> Data for " << dataName);
+
+  Ptr<CcnxNameComponents> name = Create<CcnxNameComponents> ();
+  istringstream is (dataName);
+  is >> *name;
+
+  static CcnxContentObjectTail trailer;
+  
+  CcnxContentObjectHeader data;
+  data.SetName (name);
+  data.SetFreshness (Seconds (freshness));
+
+  Ptr<Packet> packet = Create<Packet> (reinterpret_cast<const uint8_t*> (dataBuffer.c_str ()), dataBuffer.size ());
+  
+  packet->AddHeader (data);
+  packet->AddTrailer (trailer);
+
+  m_protocolHandler (packet);
+
+  m_transmittedContentObjects (&data, packet, this, m_face);
+
+  return 0;
+}
+
+int CcnxWrapper::sendInterest (const string &strInterest, const DataCallback &dataCallback)
+{
+  // NS_LOG_INFO ("Requesting Interest: \n" << interestHeader);
+  _LOG_INFO ("> Interest for " << strInterest);
+
+  Ptr<CcnxNameComponents> name = Create<CcnxNameComponents> ();
+  istringstream is (strInterest);
+  is >> *name;
+  
+  CcnxInterestHeader interestHeader;
+  interestHeader.SetNonce            (m_rand.GetValue ());
+  interestHeader.SetName             (name);
+  interestHeader.SetInterestLifetime (Seconds (4.0));
+
+  Ptr<Packet> packet = Create<Packet> ();
+  packet->AddHeader (interestHeader);
+
+  // NS_LOG_DEBUG (interestHeader);
+  
+  m_protocolHandler (packet);
+
+  m_transmittedInterests (&interestHeader, this, m_face);
+
+  // Record the callback
+  CcnxFilterEntryContainer<DataCallback>::type::iterator entry = m_dataCallbacks.find (*name);
+  if (entry == m_dataCallbacks.end ())
+    {
+      pair<CcnxFilterEntryContainer<DataCallback>::type::iterator, bool> status =
+        m_dataCallbacks.insert (CcnxFilterEntry<DataCallback> (name));
+
+      entry = status.first;
+    }
+  m_dataCallbacks.modify (entry, ll::bind (&CcnxFilterEntry<DataCallback>::AddCallback, ll::_1, dataCallback));
+  
+  return 0;
+}
+
+int CcnxWrapper::setInterestFilter (const string &prefix, const InterestCallback &interestCallback)
+{
+  Ptr<CcnxNameComponents> name = Create<CcnxNameComponents> ();
+  istringstream is (prefix);
+  is >> *name;
+
+  CcnxFilterEntryContainer<InterestCallback>::type::iterator entry = m_interestCallbacks.find (*name);
+  if (entry == m_interestCallbacks.end ())
+    {
+      pair<CcnxFilterEntryContainer<InterestCallback>::type::iterator, bool> status =
+        m_interestCallbacks.insert (CcnxFilterEntry<InterestCallback> (name));
+
+      entry = status.first;
+    }
+
+  m_interestCallbacks.modify (entry, ll::bind (&CcnxFilterEntry<InterestCallback>::AddCallback, ll::_1, interestCallback));
+
+  // creating actual face
+  
+  Ptr<CcnxFib> fib = GetNode ()->GetObject<CcnxFib> ();
+  CcnxFibEntryContainer::type::iterator fibEntry = fib->Add (*name, m_face, 0);
+
+  // make face green, so it will be used primarily
+  fib->m_fib.modify (fibEntry,
+                     ll::bind (&CcnxFibEntry::UpdateStatus,
+                               ll::_1, m_face, CcnxFibFaceMetric::NDN_FIB_GREEN));
+
+  return 0;
+}
+
+void
+CcnxWrapper::clearInterestFilter (const std::string &prefix)
+{
+  Ptr<CcnxNameComponents> name = Create<CcnxNameComponents> ();
+  istringstream is (prefix);
+  is >> *name;
+
+  CcnxFilterEntryContainer<InterestCallback>::type::iterator entry = m_interestCallbacks.find (*name);
+  if (entry == m_interestCallbacks.end ())
+    return;
+
+  m_interestCallbacks.modify (entry, ll::bind (&CcnxFilterEntry<InterestCallback>::ClearCallback, ll::_1));  
+}
+
+CcnxFilterEntryContainer<CcnxWrapper::InterestCallback>::type::iterator
+CcnxWrapper::InterestCallbackLookup (const ns3::CcnxNameComponents &name)
+{
+  CcnxFilterEntryContainer<InterestCallback>::type::iterator entry = m_interestCallbacks.end ();
+
+  // do the longest prefix match
+  for (size_t componentsCount = name.GetComponents ().size ()+1;
+       componentsCount > 0;
+       componentsCount--)
+    {
+      CcnxNameComponents subPrefix (name.GetSubComponents (componentsCount-1));
+
+      entry = m_interestCallbacks.find (subPrefix);
+      if (entry != m_interestCallbacks.end())
+        return entry;
+    }
+
+  return entry;
+}
+
+CcnxFilterEntryContainer<CcnxWrapper::DataCallback>::type::iterator
+CcnxWrapper::DataCallbackLookup (const ns3::CcnxNameComponents &name)
+{
+  CcnxFilterEntryContainer<DataCallback>::type::iterator entry = m_dataCallbacks.end ();
+
+  // do the longest prefix match
+  for (size_t componentsCount = name.GetComponents ().size ()+1;
+       componentsCount > 0;
+       componentsCount--)
+    {
+      CcnxNameComponents subPrefix (name.GetSubComponents (componentsCount-1));
+
+      entry = m_dataCallbacks.find (subPrefix);
+      if (entry != m_dataCallbacks.end())
+        return entry;
+    }
+
+  return entry;  
+}
+
+void
+CcnxWrapper::OnInterest (const Ptr<const CcnxInterestHeader> &interest, Ptr<Packet> packet)
+{
+  CcnxApp::OnInterest (interest, packet);
+
+  CcnxFilterEntryContainer<InterestCallback>::type::iterator entry = InterestCallbackLookup (interest->GetName ());
+  if (entry == m_interestCallbacks.end ())
+    {
+      _LOG_DEBUG ("No Interest callback set");
+      return;
+    }
+  
+  entry->m_callback (lexical_cast<string> (interest->GetName ()));  
+}
+
+void
+CcnxWrapper::OnContentObject (const Ptr<const CcnxContentObjectHeader> &contentObject,
+                              Ptr<Packet> payload)
+{
+  CcnxApp::OnContentObject (contentObject, payload);
+
+  CcnxFilterEntryContainer<DataCallback>::type::iterator entry = DataCallbackLookup (contentObject->GetName ());
+  if (entry == m_dataCallbacks.end ())
+    {
+      _LOG_DEBUG ("No Data callback set");
+      return;
+    }
+
+  ostringstream content;
+  payload->CopyData (&content, payload->GetSize ());
+  
+  entry->m_callback (lexical_cast<string> (contentObject->GetName ()), content.str ());
+  
+  // i guess it make sense to remove callback when interest is satisfied
+  m_dataCallbacks.erase (entry);
+}
+
+
+}
diff --git a/ns3/sync-ccnx-wrapper.h b/ns3/sync-ccnx-wrapper.h
new file mode 100644
index 0000000..5776c1a
--- /dev/null
+++ b/ns3/sync-ccnx-wrapper.h
@@ -0,0 +1,195 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 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: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ *         Chaoyi Bian <bcy@pku.edu.cn>
+ *	   Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef SYNC_CCNX_WRAPPER_H
+#define SYNC_CCNX_WRAPPER_H
+
+#include <boost/exception/all.hpp>
+#include <boost/function.hpp>
+#include <string>
+
+#include <ns3/ptr.h>
+#include <ns3/node.h>
+#include <ns3/random-variable.h>
+#include <ns3/ccnx-app.h>
+#include <ns3/ccnx-name-components.h>
+#include <ns3/hash-helper.h>
+
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/mem_fun.hpp>
+
+/**
+ * \defgroup sync SYNC protocol
+ *
+ * Implementation of SYNC protocol
+ */
+namespace Sync {
+
+template<class Callback>
+struct CcnxFilterEntry
+{
+public:
+  CcnxFilterEntry (ns3::Ptr<const ns3::CcnxNameComponents> prefix)
+    : m_prefix (prefix)
+  { }
+  
+  const ns3::CcnxNameComponents &
+  GetPrefix () const
+  { return *m_prefix; }
+
+  void
+  AddCallback (Callback callback)
+  { 
+    m_callback = callback;
+  }
+
+  void
+  ClearCallback ()
+  {
+    m_callback = 0;
+  }
+  
+public:
+  ns3::Ptr<const ns3::CcnxNameComponents> m_prefix; ///< \brief Prefix of the PIT entry
+  Callback m_callback;
+};
+
+
+template<class Callback>
+struct CcnxFilterEntryContainer
+{
+  typedef
+  boost::multi_index::multi_index_container<
+    CcnxFilterEntry<Callback>,
+    boost::multi_index::indexed_by<
+      // indexed by hash
+      boost::multi_index::hashed_unique<
+        boost::multi_index::const_mem_fun< CcnxFilterEntry<Callback>, const ns3::CcnxNameComponents&, &CcnxFilterEntry<Callback>::GetPrefix >,
+        ns3::CcnxPrefixHash
+        >
+      >
+    > type;
+};
+
+
+
+struct CcnxOperationException : virtual boost::exception, virtual std::exception { };
+/**
+ * \ingroup sync
+ * @brief A wrapper for ccnx library; clients of this code do not need to deal
+ * with ccnx library
+ */
+class CcnxWrapper
+  : public ns3::CcnxApp
+{
+public:
+  typedef boost::function<void (std::string, std::string)> DataCallback;
+  typedef boost::function<void (std::string)> InterestCallback;
+  
+  /**
+   * @brief initialize the wrapper; a lot of things needs to be done. 1) init
+   * keystore 2) init keylocator 3) start a thread to hold a loop of ccn_run
+   *
+   */
+  CcnxWrapper();
+  ~CcnxWrapper();
+
+  // from CcnxApp
+  /**
+   * @brief Should be called after Node pointer is set to create face and start application
+   */
+  virtual void
+  StartApplication ();
+
+  /**
+   * @brief Stop application
+   */
+  virtual void
+  StopApplication ();
+
+  /**
+   * @brief send Interest; need to grab lock m_mutex first
+   *
+   * @param strInterest the Interest name
+   * @param dataCallback the callback function to deal with the returned data
+   * @return the return code of ccn_express_interest
+   */
+  int
+  sendInterest (const std::string &strInterest, const DataCallback &dataCallback);
+
+  /**
+   * @brief set Interest filter (specify what interest you want to receive)
+   *
+   * @param prefix the prefix of Interest
+   * @param interestCallback the callback function to deal with the returned data
+   * @return the return code of ccn_set_interest_filter
+   */
+  int
+  setInterestFilter (const std::string &prefix, const InterestCallback &interestCallback);
+
+  /**
+   * @brief clear Interest filter
+   * @param prefix the prefix of Interest
+   */
+  void
+  clearInterestFilter (const std::string &prefix);
+
+  /**
+   * @brief publish data and put it to local ccn content store; need to grab
+   * lock m_mutex first
+   *
+   * @param name the name for the data object
+   * @param dataBuffer the data to be published
+   * @param freshness the freshness time for the data object
+   * @return code generated by ccnx library calls, >0 if success
+   */
+  int
+  publishData (const std::string &name, const std::string &dataBuffer, int freshness);
+
+  // from CcnxApp
+  virtual void
+  OnInterest (const ns3::Ptr<const ns3::CcnxInterestHeader> &interest, ns3::Ptr<ns3::Packet> packet);
+ 
+  virtual void
+  OnContentObject (const ns3::Ptr<const ns3::CcnxContentObjectHeader> &contentObject,
+                   ns3::Ptr<ns3::Packet> payload);
+
+private:
+  CcnxFilterEntryContainer<InterestCallback>::type::iterator
+  InterestCallbackLookup (const ns3::CcnxNameComponents &name);
+
+  CcnxFilterEntryContainer<DataCallback>::type::iterator
+  DataCallbackLookup (const ns3::CcnxNameComponents &name);
+
+private:
+  ns3::UniformVariable m_rand; // nonce generator
+
+  CcnxFilterEntryContainer<DataCallback>::type m_dataCallbacks;
+  CcnxFilterEntryContainer<InterestCallback>::type m_interestCallbacks;
+};
+
+typedef boost::shared_ptr<CcnxWrapper> CcnxWrapperPtr;
+
+} // Sync
+
+#endif // SYNC_CCNX_WRAPPER_H
diff --git a/ns3/sync-log.h b/ns3/sync-log.h
new file mode 100644
index 0000000..6dbc930
--- /dev/null
+++ b/ns3/sync-log.h
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 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: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ *         Chaoyi Bian <bcy@pku.edu.cn>
+ *	   Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef SYNC_LOG_H
+#define SYNC_LOG_H
+
+#ifdef NS3_MODULE
+
+#include <ns3/log.h>
+
+#define INIT_LOGGER(name) NS_LOG_COMPONENT_DEFINE(name);
+
+#define _LOG_INFO(x) NS_LOG_INFO(x)
+
+#define _LOG_DEBUG(x) NS_LOG_DEBUG(x)
+
+#define _LOG_TRACE(x) NS_LOG_LOGIC(x)
+
+#define _LOG_FUNCTION(x) NS_LOG_FUNCTION(x)
+
+#define _LOG_FUNCTION_NOARGS NS_LOG_FUNCTION_NOARGS
+
+#else
+
+#ifdef HAVE_LOG4CXX
+
+#include <log4cxx/logger.h>
+
+#define INIT_LOGGER(name) \
+  static log4cxx::LoggerPtr staticModuleLogger = log4cxx::Logger::getLogger (name);
+
+#define _LOG_INFO(x) \
+  LOG4CXX_INFO(staticModuleLogger, x);
+
+#define _LOG_DEBUG(x)                           \
+  LOG4CXX_DEBUG(staticModuleLogger, x);
+
+#define _LOG_TRACE(x) \
+  LOG4CXX_TRACE(staticModuleLogger, x);
+
+#define _LOG_FUNCTION(x) \
+  LOG4CXX_TRACE(staticModuleLogger, __FUNCTION__ << "(" << x << ")");
+
+#define _LOG_FUNCTION_NOARGS \
+  LOG4CXX_TRACE(staticModuleLogger, __FUNCTION__ << "()");
+
+void
+INIT_LOGGERS ();
+
+#else
+
+#define INIT_LOGGER(name)
+#define _LOG_FUNCTION(x)
+#define _LOG_FUNCTION_NOARGS
+#define _LOG_TRACE(x)
+#define _LOG_INFO(x)
+#define INIT_LOGGERS(x)
+
+#ifdef _DEBUG
+
+#include <boost/thread/thread.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <iostream>
+
+#define _LOG_DEBUG(x) \
+  std::clog << boost::get_system_time () << " " << boost::this_thread::get_id () << " " << x << endl;
+
+#else
+#define _LOG_DEBUG(x)
+#endif
+
+#endif // HAVE_LOG4CXX
+
+#endif // NS3_MODULE
+
+#endif // SYNC_LOG_H
diff --git a/model/sync-ns3-name-info.cc b/ns3/sync-ns3-name-info.cc
similarity index 82%
rename from model/sync-ns3-name-info.cc
rename to ns3/sync-ns3-name-info.cc
index b46d1f6..dfd6179 100644
--- a/model/sync-ns3-name-info.cc
+++ b/ns3/sync-ns3-name-info.cc
@@ -35,25 +35,35 @@
 
 namespace Sync {
 
-
 NameInfoConstPtr
 Ns3NameInfo::FindOrCreate (ns3::Ptr<const ns3::CcnxNameComponents> name)
 {
+  mutex::scoped_lock namesLock (m_namesMutex);
+  
+  NameInfoConstPtr ret;
   string key = lexical_cast<string> (*name);
-
+  
   NameMap::iterator item = m_names.find (key);
-  if (item == m_names.end ())
+  if (item != m_names.end ())
     {
-      NameInfoPtr value = NameInfoPtr (new Ns3NameInfo (name));
+      ret = item->second.lock ();
+      BOOST_ASSERT (ret != 0);
+    }
+  else
+    {
+      ret = NameInfoPtr (new Ns3NameInfo (name));
+      weak_ptr<const NameInfo> value (ret);
       pair<NameMap::iterator,bool> inserted =
         m_names.insert (make_pair (key, value));
+      
       BOOST_ASSERT (inserted.second); // previous call has to insert value
       item = inserted.first;
     }
 
-  return item->second;
+  return ret;
 }
 
+
 Ns3NameInfo::Ns3NameInfo (ns3::Ptr<const ns3::CcnxNameComponents> name)
   : m_name (name)
 {
@@ -81,6 +91,19 @@
     }
 }
 
+bool
+Ns3NameInfo::operator < (const NameInfo &info) const
+{
+  try
+    {
+      return *m_name < *dynamic_cast<const Ns3NameInfo&> (info).m_name;
+    }
+  catch (...)
+    {
+      return false;
+    }
+}
+
 Digest &
 operator << (Digest &digest, const ns3::CcnxNameComponents &name)
 {
diff --git a/model/sync-ns3-name-info.h b/ns3/sync-ns3-name-info.h
similarity index 96%
rename from model/sync-ns3-name-info.h
rename to ns3/sync-ns3-name-info.h
index 9363665..347ba1a 100644
--- a/model/sync-ns3-name-info.h
+++ b/ns3/sync-ns3-name-info.h
@@ -47,6 +47,9 @@
   virtual bool
   operator == (const NameInfo &info) const;
 
+  virtual bool
+  operator < (const NameInfo &info) const;
+
   virtual std::string
   toString () const;
 
diff --git a/ns3/sync-scheduler.cc b/ns3/sync-scheduler.cc
new file mode 100644
index 0000000..7f39f38
--- /dev/null
+++ b/ns3/sync-scheduler.cc
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 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: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ *         Chaoyi Bian <bcy@pku.edu.cn>
+ *	   Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "sync-scheduler.h"
+#include "sync-log.h"
+
+#include "ns3/simulator.h"
+
+using namespace boost;
+using namespace std;
+using namespace ns3;
+
+INIT_LOGGER ("Scheduler");
+
+namespace Sync {
+
+Scheduler::Scheduler ()
+{
+}
+
+Scheduler::~Scheduler ()
+{
+}
+
+void
+Scheduler::eventWrapper (Event event)
+{
+  event ();
+}
+
+void
+Scheduler::schedule (const TimeDuration &reltime, Event event, uint32_t label)
+{
+  list< EventId > &eventsForLabel = m_labeledEvents [label];
+  list< EventId >::iterator i = eventsForLabel.begin ();
+  while (i != eventsForLabel.end ())
+    {
+      if (i->IsExpired ())
+        {
+          list< EventId >::iterator next = i;
+          next ++;
+          eventsForLabel.erase (i);
+          i = next;
+        }
+      else
+        i ++;
+    }
+
+  ns3::EventId eventId = ns3::Simulator::Schedule (reltime, Scheduler::eventWrapper, event);
+  eventsForLabel.push_back (eventId);
+}
+
+void
+Scheduler::cancel (uint32_t label)
+{
+  list< EventId > &eventsForLabel = m_labeledEvents [label];
+
+  for (list< EventId >::iterator i = eventsForLabel.begin ();
+       i != eventsForLabel.end ();
+       i++)
+    {
+      i->Cancel ();
+    }
+
+  eventsForLabel.clear ();
+}
+
+
+} // Sync
diff --git a/model/sync-scheduler.h b/ns3/sync-scheduler.h
similarity index 75%
copy from model/sync-scheduler.h
copy to ns3/sync-scheduler.h
index 10ef210..f10dc70 100644
--- a/model/sync-scheduler.h
+++ b/ns3/sync-scheduler.h
@@ -23,10 +23,16 @@
 #ifndef SYNC_SCHEDULER_H
 #define SYNC_SCHEDULER_H
 
-#include <boost/thread/thread.hpp>
-#include <boost/thread/mutex.hpp>
+#include <ns3/nstime.h>
+#include <ns3/event-id.h>
+#include <list>
+#include <map>
 
-#include "sync-logic-event-container.h"
+#include "sync-event.h"
+
+#define TIME_SECONDS(number) ns3::Seconds(number)
+#define TIME_MILLISECONDS(number) ns3::MilliSeconds(number)
+typedef ns3::Time TimeDuration;
 
 namespace Sync {
 
@@ -54,8 +60,8 @@
    * @param event function to be called at the time
    * @param label Label for the event
    */
-  void
-  schedule (const boost::system_time &abstime, Event event, uint32_t label);
+  // void
+  // schedule (const boost::system_time &abstime, Event event, uint32_t label);
 
   /**
    * @brief Schedule an event at relative time 'reltime'
@@ -64,7 +70,7 @@
    * @param label Label for the event
    */
   void
-  schedule (const boost::posix_time::time_duration &reltime, Event event, uint32_t label); 
+  schedule (const TimeDuration &reltime, Event event, uint32_t label); 
 
   /**
    * @brief Cancel all events for the label
@@ -73,26 +79,12 @@
   void
   cancel (uint32_t label);
 
-#ifdef _DEBUG
-  size_t
-  getEventsSize ()
-  {
-    boost::lock_guard<boost::mutex> lock (m_eventsMutex);
-    return m_events.size ();
-  }
-#endif
-  
 private:
-  void
-  threadLoop ();
-    
-private:
-  EventsContainer m_events;
-  boost::condition_variable m_eventsCondition;
-  boost::mutex  m_eventsMutex;
+  static void
+  eventWrapper (Event event);
 
-  boost::thread m_thread;
-  bool          m_threadRunning;
+private:
+  std::map< uint32_t, std::list< ns3::EventId > > m_labeledEvents;
 };
   
 }
diff --git a/test/test_app_socket.cc b/test/test_app_socket.cc
index e9a87fc..985dac3 100644
--- a/test/test_app_socket.cc
+++ b/test/test_app_socket.cc
@@ -27,9 +27,9 @@
 #include <boost/make_shared.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
 
-#include "../model/sync-log.h"
+#include "sync-log.h"
 
-#include "../model/sync-app-socket.h"
+#include "sync-app-socket.h"
 extern "C" {
 #include <unistd.h>
 }
diff --git a/test/test_ccnx_wrapper.cc b/test/test_ccnx_wrapper.cc
index ac5150c..6934584 100644
--- a/test/test_ccnx_wrapper.cc
+++ b/test/test_ccnx_wrapper.cc
@@ -26,7 +26,7 @@
 
 #include <boost/make_shared.hpp>
 
-#include "../model/sync-ccnx-wrapper.h"
+#include "sync-ccnx-wrapper.h"
 
 using namespace Sync;
 using namespace std;
diff --git a/test/test_data_fetch_and_publish.cc b/test/test_data_fetch_and_publish.cc
index 0d5417d..157ce7f 100644
--- a/test/test_data_fetch_and_publish.cc
+++ b/test/test_data_fetch_and_publish.cc
@@ -27,9 +27,9 @@
 
 #include <boost/make_shared.hpp>
 
-#include "../model/sync-ccnx-wrapper.h"
-#include "../model/sync-app-data-fetch.h"
-#include "../model/sync-app-data-publish.h"
+#include "sync-ccnx-wrapper.h"
+#include "sync-app-data-fetch.h"
+#include "sync-app-data-publish.h"
 
 using namespace Sync;
 using namespace std;
diff --git a/test/test_digest.cc b/test/test_digest.cc
index d7ddbf5..8afd88b 100644
--- a/test/test_digest.cc
+++ b/test/test_digest.cc
@@ -25,7 +25,7 @@
 #include <boost/test/output_test_stream.hpp> 
 using boost::test_tools::output_test_stream;
 
-#include "../model/sync-digest.h"
+#include "sync-digest.h"
 #include <iostream>
 #include <sstream>
 
diff --git a/test/test_interest_table.cc b/test/test_interest_table.cc
index 6727bcc..34ea00f 100644
--- a/test/test_interest_table.cc
+++ b/test/test_interest_table.cc
@@ -27,7 +27,7 @@
 
 #include <boost/make_shared.hpp>
 
-#include "../model/sync-interest-table.h"
+#include "sync-interest-table.h"
 
 using namespace Sync;
 using namespace std;
diff --git a/test/test_leaf.cc b/test/test_leaf.cc
index 0c8409f..361793a 100644
--- a/test/test_leaf.cc
+++ b/test/test_leaf.cc
@@ -26,9 +26,9 @@
 
 #include <boost/make_shared.hpp>
 
-#include "../model/sync-full-leaf.h"
-#include "../model/sync-diff-leaf.h"
-#include "../model/sync-std-name-info.h"
+#include "sync-full-leaf.h"
+#include "sync-diff-leaf.h"
+#include "sync-std-name-info.h"
 
 using namespace Sync;
 using namespace std;
diff --git a/test/test_pit.cc b/test/test_pit.cc
index 7b2c7af..dca697e 100644
--- a/test/test_pit.cc
+++ b/test/test_pit.cc
@@ -27,8 +27,8 @@
 
 #include <boost/make_shared.hpp>
 
-#include "../model/sync-interest-table.h"
-#include "../model/sync-log.h"
+#include "sync-interest-table.h"
+#include "sync-log.h"
 
 using namespace Sync;
 using namespace std;
diff --git a/test/test_scheduler.cc b/test/test_scheduler.cc
index 276fd50..59687e4 100644
--- a/test/test_scheduler.cc
+++ b/test/test_scheduler.cc
@@ -26,8 +26,8 @@
 using boost::test_tools::output_test_stream;
 
 #include <boost/make_shared.hpp>
-#include "../model/sync-scheduler.h"
-#include "../model/sync-logic.h"
+#include "sync-scheduler.h"
+#include "sync-logic.h"
 
 using namespace Sync;
 using namespace std;
diff --git a/test/test_state.cc b/test/test_state.cc
index 86d4c6f..35fc79c 100644
--- a/test/test_state.cc
+++ b/test/test_state.cc
@@ -30,9 +30,9 @@
 #include <boost/make_shared.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
 
-#include "../model/sync-std-name-info.h"
-#include "../model/sync-full-state.h"
-#include "../model/sync-diff-state.h"
+#include "sync-std-name-info.h"
+#include "sync-full-state.h"
+#include "sync-diff-state.h"
 
 using namespace Sync;
 using namespace std;
diff --git a/test/test_sync_logic.cc b/test/test_sync_logic.cc
index 5b36ba8..f6b6808 100644
--- a/test/test_sync_logic.cc
+++ b/test/test_sync_logic.cc
@@ -27,9 +27,9 @@
 
 #include <boost/make_shared.hpp>
 
-#include "../model/sync-ccnx-wrapper.h"
-#include "../model/sync-logic.h"
-#include "../model/sync-seq-no.h"
+#include "sync-ccnx-wrapper.h"
+#include "sync-logic.h"
+#include "sync-seq-no.h"
 
 using namespace std;
 using namespace boost;
diff --git a/waf-tools/ns3.py b/waf-tools/ns3.py
new file mode 100644
index 0000000..5f5595e
--- /dev/null
+++ b/waf-tools/ns3.py
@@ -0,0 +1,66 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+import waflib
+from waflib.Configure import conf
+from waflib import Utils,Logs,Errors
+
+@conf
+def _print_optional_features(conf):
+    # Write a summary of optional features status
+    print "---- Summary of optional NS-3 features:"
+    Logs.pprint ('RED', "---- Summary of optional NS-3 features:")
+    # for (name, caption, was_enabled, reason_not_enabled) in conf.env['NS3_OPTIONAL_FEATURES']:
+    #     if was_enabled:
+    #         status = 'enabled'
+    #     else:
+    #         status = 'not enabled (%s)' % reason_not_enabled
+    #     print "%-30s: %s" % (caption, status)
+
+@conf
+def _check_dependencies(conf, required, mandatory):
+    # Logs.pprint ('CYAN', '  + %s' % required)
+    found = []
+    for module in required:
+        retval = conf.check_cfg(package = 'libns3-dev-%s-debug' % module,
+                                args='--cflags --libs', mandatory=mandatory,
+                                msg="Checking for ns3-%s" % module,
+                                uselib_store='NS3_%s' % module.upper())
+        # Logs.pprint ('CYAN', 'NS3_%s' % module.upper())
+        if not retval is None:
+            found.append(module)
+    import copy
+    if not 'NS3_MODULES_FOUND' in conf.env:
+        conf.env['NS3_MODULES_FOUND'] = []
+    conf.env['NS3_MODULES_FOUND'] = conf.env['NS3_MODULES_FOUND'] + copy.copy(found)
+
+def modules_uselib(bld, names):
+    return ['NS3_%s' % name.upper() for name in names] + \
+        ['NS3_LIBRARY_%s' % name.upper() for name in names] + \
+        ['NS3_HEADERS_%s' % name.upper() for name in names]
+
+def modules_found(bld, needed):
+    for module in needed:
+        if not module in bld.env['NS3_MODULES_FOUND']:
+            return False
+    return True
+
+@conf
+def check_modules(conf, modules, mandatory = True):
+    import os
+
+    if not 'NS3_CHECK_MODULE_ONCE' in conf.env:
+        conf.env['NS3_CHECK_MODULE_ONCE'] = ''
+
+        conf.check_cfg(atleast_pkgconfig_version='0.0.0')
+
+        if conf.options.log4cxx:
+            conf.env.append_value('DEFINES', 'NS3_LOG_ENABLE')
+
+    conf._check_dependencies(modules, mandatory)
+    conf._print_optional_features
+
+@conf
+def print_ns3_feature_summary(conf):
+    Logs.pprint ('CYAN', "---- Summary of optional NS-3 features:")
+    conf._print_optional_features
+
diff --git a/wscript b/wscript
index 6a0a629..eaf1d13 100644
--- a/wscript
+++ b/wscript
@@ -5,16 +5,16 @@
 
 def options(opt):
     opt.add_option('--no-debug',action='store_true',default=False,dest='no_debug',help='''Make an optimized build of the library (remove debugging code)''')
-    opt.add_option('--log4cxx',action='store_true',default=False,dest='log4cxx',help='''Compile with log4cxx support''')
+    opt.add_option('--log4cxx', action='store_true',default=False,dest='log4cxx',help='''Compile with log4cxx/native NS3 logging support''')
+    opt.add_option('--ns3',     action='store_true',default=False,dest='ns3_enable',help='''Compile as NS-3 module''')
     opt.load('compiler_c')
     opt.load('compiler_cxx')
     opt.load('boost')
     opt.load('doxygen')
-    opt.load('ccnx tinyxml', tooldir=["waf-tools"])
+    opt.load('ccnx tinyxml ns3', tooldir=["waf-tools"])
 
 def configure(conf):
     conf.load("compiler_cxx")
-    conf.env.append_value('CXXFLAGS', ['-O0', '-g3'])
 
     if not conf.check_cfg(package='openssl', args=['--cflags', '--libs'], uselib_store='SSL', mandatory=False):
       libcrypto = conf.check_cc(lib='crypto',
@@ -25,40 +25,124 @@
         conf.fatal ("Cannot find SSL libraries")
 
     conf.load('boost')
-    conf.check_boost(lib='system iostreams test thread')
-    
+
+    if conf.options.ns3_enable:
+        conf.load('ns3')
+        conf.define('NS3_MODULE', 1)
+        conf.check_modules(['core', 'network', 'internet'], mandatory = True)
+        conf.check_modules(['NDNabstraction'], mandatory = True)
+        conf.check_modules(['point-to-point'], mandatory = False)
+        conf.check_modules(['point-to-point-layout'], mandatory = False)
+
+        conf.check_boost(lib='system iostreams thread')
+        conf.define ('NS3_LOG_ENABLE', 1)
+    else:
+        conf.check_boost(lib='system iostreams test thread')
+        conf.define ('STANDALONE', 1)
+
+        conf.load ('ccnx')
+        conf.check_ccnx (path=conf.options.ccnx_dir)
+
+        if conf.options.log4cxx:
+            conf.check_cfg(package='liblog4cxx', args=['--cflags', '--libs'], uselib_store='LOG4CXX', mandatory=True)
+
+    if not conf.options.no_debug:
+        conf.define ('_DEBUG', 1)
+        conf.env.append_value('CXXFLAGS', ['-O0', '-g3'])
+    else:
+        conf.env.append_value('CXXFLAGS', ['-O3'])
+
     try:
         conf.load('doxygen')
     except:
         pass
 
-    conf.load('ccnx tinyxml')
-    conf.check_ccnx (path=conf.options.ccnx_dir)
-    conf.check_tinyxml (path=conf.options.ccnx_dir)
-
-    conf.define ('STANDALONE', 1)
-    if not conf.options.no_debug:
-        conf.define ('_DEBUG', 1)
-
-    if conf.options.log4cxx:
-        conf.check_cfg(package='liblog4cxx', args=['--cflags', '--libs'], uselib_store='LOG4CXX', mandatory=True)
+    conf.load('tinyxml')
+    conf.check_tinyxml ()
                    
 def build (bld):
-    libsync = bld.shlib (target=APPNAME, 
-                         features=['cxx', 'cxxshlib'],
-                         source = bld.path.ant_glob(['model/sync-*.cc',
-                                                     'helper/sync-*.cc']),
-                         use = 'BOOST BOOST_IOSTREAMS BOOST_THREAD SSL TINYXML CCNX')
+    if bld.get_define ("NS3_MODULE"):
+        sync_ns3 = bld.shlib (
+            target = "sync-ns3",
+            features=['cxx', 'cxxshlib'],
+            source =  [
+                'ns3/sync-ccnx-wrapper.cc',
+                'ns3/sync-ns3-name-info.cc',
+                'ns3/sync-scheduler.cc',
+                
+                # 'model/sync-app-data-fetch.cc',
+                # 'model/sync-app-data-publish.cc',
+                # 'ns3/sync-app.cc',
 
-    # Unit tests
-    unittests = bld.program (target="unit-tests",
-                             source = bld.path.ant_glob(['test/**/*.cc']),
-                             features=['cxx', 'cxxprogram'],
-                             use = 'BOOST_TEST sync')
+                'model/sync-diff-leaf.cc',
+                'model/sync-diff-state.cc',
+                'model/sync-digest.cc',
+                'model/sync-full-leaf.cc',
+                'model/sync-full-state.cc',
+                'model/sync-interest-table.cc',
+                'model/sync-leaf.cc',
+                'model/sync-logic.cc',
+                'model/sync-name-info.cc',
+                'model/sync-seq-no.cc',
+                'model/sync-state.cc',
+                'model/sync-std-name-info.cc',
+                ],
+            use = 'BOOST BOOST_IOSTREAMS SSL TINYXML CCNX ' + ' '.join (['ns3_'+dep for dep in ['core', 'network', 'internet', 'NDNabstraction']]).upper (),
+            includes = ['model', 'ns3', 'helper'],
+            )
 
-    if bld.get_define ("HAVE_LOG4CXX"):
-        libsync.use += ' LOG4CXX'
-        unittests.use += ' LOG4CXX'
+        example = bld.program (
+            target = "sync-example",
+            features=['cxx', 'cxxprogram'],
+            source = ['examples/sync-example.cc'],
+            use = 'sync-ns3',
+            includes = ['model', 'ccnx', 'helper'],
+            )
+        # from waflib import Utils,Logs,Errors
+        # Logs.pprint ('CYAN', program.use)
+        
+    else:
+        libsync = bld.shlib (
+            target=APPNAME, 
+            features=['cxx', 'cxxshlib'],
+            source =  [
+                'ccnx/sync-ccnx-wrapper.cc',
+                'ccnx/sync-scheduler.cc',
+                'ccnx/sync-log.cc',
+                'ccnx/sync-app-data-fetch.cc',
+                'ccnx/sync-app-data-publish.cc',
+                'ccnx/sync-app-socket-c.cc',
+                'ccnx/sync-app-socket.cc',
+                
+                'model/sync-diff-leaf.cc',
+                'model/sync-diff-state.cc',
+                'model/sync-digest.cc',
+                'model/sync-full-leaf.cc',
+                'model/sync-full-state.cc',
+                'model/sync-interest-table.cc',
+                'model/sync-leaf.cc',
+                'model/sync-logic.cc',
+                'model/sync-name-info.cc',
+                'model/sync-seq-no.cc',
+                'model/sync-state.cc',
+                'model/sync-std-name-info.cc',
+                ],
+            use = 'BOOST BOOST_IOSTREAMS BOOST_THREAD SSL TINYXML CCNX',
+            includes = ['model', 'ccnx', 'helper'],
+            )
+        
+        # Unit tests
+        unittests = bld.program (
+            target="unit-tests",
+            source = bld.path.ant_glob(['test/**/*.cc']),
+            features=['cxx', 'cxxprogram'],
+            use = 'BOOST_TEST sync',
+            includes = ['model', 'ccnx', 'helper'],
+            )
+
+        if bld.get_define ("HAVE_LOG4CXX"):
+            libsync.use += ' LOG4CXX'
+            unittests.use += ' LOG4CXX'
 
 # doxygen docs
 from waflib.Build import BuildContext