Merge remote-tracking branch 'git.irl/master'
diff --git a/include/event-scheduler.h b/include/event-scheduler.h
new file mode 100644
index 0000000..72169d8
--- /dev/null
+++ b/include/event-scheduler.h
@@ -0,0 +1,137 @@
+#ifndef EVENT_SCHEDULER_H
+#define EVENT_SCHEDULER_H
+#include <event2/event.h>
+#include <event2/event_struct.h>
+#include <event2/thread.h>
+
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_real.hpp>
+#include <boost/random/variate_generator.hpp>
+#include <boost/exception/all.hpp>
+#include <math.h>
+#include <multimap>
+
+#define _OVERRIDE
+#ifdef __GNUC__
+#if __GNUC_MAJOR >= 4 && __GNUC_MINOR__ >= 7
+  #undef _OVERRIDE
+  #define _OVERRIDE override
+#endif // __GNUC__ version
+#endif // __GNUC__
+
+using namespace std;
+
+
+class Task
+{
+public:
+  typedef boost::function<void (void *)> Callback;
+  typedef string Tag;
+  typedef boost::function<bool (const Task &task)> TaskMatcher;
+
+  Task(const Callback &callback, void *arg, const Tag &tag);
+  Task(const Task &other);
+  Task &
+  operator=(const Task &other);
+
+  virtual void
+  run() { m_callback(m_arg); }
+
+  Tag
+  tag() { return m_tag; }
+
+
+protected:
+  Callback m_callback;
+  Tag m_tag;
+  void *arg;
+};
+
+struct SchedulerException : virtual boost::exception, virtual exception { };
+
+class IntervalGenerator;
+typedef boost::shared_ptr<IntervalGenerator> IntervalGeneratorPtr;
+class Scheduler
+{
+public:
+  Scheduler();
+  virtual ~Scheduler();
+
+  virtual void
+  start();
+
+  virtual void
+  shutdown();
+
+  virtual void
+  addTask(const Task &task, double delay);
+
+  virtual void
+  addTimeoutTask(const Task &task, double timeout);
+
+  virtual void
+  addPeriodicTask(const Task &task, const IntervalGeneratorPtr &generator);
+
+  virtual void
+  deleteTask(const Tag &tag);
+
+  virtual void
+  deleteTask(const TaskMatcher &matcher);
+
+protected:
+  typedef multimap<Tag, Task> TaskMap;
+  TaskMap m_taskMap;
+};
+
+class IntervalGenerator
+{
+public:
+  virtual double
+  nextInterval() = 0;
+};
+
+class SimpleIntervalGenerator : IntervalGenerator
+{
+public:
+  SimpleIntervalGenerator(double interval) : m_interval(interval) {}
+  ~SimpleIntervalGenerator(){}
+  virtual double
+  nextInterval() _OVERRIDE { return m_interval; }
+private:
+  SimpleIntervalGenerator(const SimpleIntervalGenerator &other){};
+private:
+  double m_interval;
+};
+
+class RandomIntervalGenerator : IntervalGenerator
+{
+  typedef enum
+  {
+    UP,
+    DOWN,
+    EVEN
+  } Direction;
+
+public:
+  RandomIntervalGenerator(double interval, double percent, Direction direction = EVEN);
+  ~RandomIntervalGenerator(){}
+  virtual double
+  nextInterval() _OVERRIDE;
+
+private:
+  RandomIntervalGenerator(const RandomIntervalGenerator &other){};
+  inline double fractional(double x) { double dummy; return abs(modf(x, &dummy)); }
+
+private:
+  typedef boost::mt19937 RNG_TYPE;
+  RNG_TYPE m_rng;
+  boost::uniform_real<> m_dist;
+  boost::rariate_generator<RNG_TYPE &, boost::uniform_real<> > m_random;
+  Direction m_direction;
+  double m_interval;
+  double m_percent;
+
+};
+#endif // EVENT_SCHEDULER_H
diff --git a/src/event-scheduler.cpp b/src/event-scheduler.cpp
new file mode 100644
index 0000000..b823255
--- /dev/null
+++ b/src/event-scheduler.cpp
@@ -0,0 +1,49 @@
+#include "event-scheduler.h"
+
+Task::Task(const Callback &callback, void *arg, const Tag &tag)
+     : m_callback(callback)
+     , m_arg(arg)
+     , m_tag(tag)
+{
+}
+
+Task::Task(const Task &other)
+     : m_callback(other.m_callback)
+     , m_arg(other.m_arg)
+     , m_tag(other.m_tag)
+{
+}
+
+Task &
+Task::operator=(const Task &other)
+{
+  m_callback = other.m_callback;
+  m_arg = other.m_arg;
+  m_tag = other.m_tag;
+  return (*this);
+}
+
+RandomIntervalGenerator::RandomIntervalGenerator(double interval, double percent, Direction direction = UP)
+                        : m_interval(interval)
+                        , m_rng(time(NULL))
+                        , m_percent(percent)
+                        , m_dist(0.0, fractional(percent))
+                        , m_random(m_rng, m_dist)
+{
+}
+
+double
+RandomIntervalGenerator::nextInterval()
+{
+  double percent = m_random();
+  double interval = m_interval;
+  switch (m_direction)
+  {
+  case UP: interval = m_interval * (1.0 + percent); break;
+  case DOWN: interval = m_interval * (1.0 - percent); break;
+  case EVEN: interval = m_interval * (1.0 - m_percent/2.0 + percent); break;
+  default: break
+  }
+
+  return interval;
+}
diff --git a/test/test-ccnx-tunnel.cc b/test/test-ccnx-tunnel.cc
index 03f4250..5a5abc5 100644
--- a/test/test-ccnx-tunnel.cc
+++ b/test/test-ccnx-tunnel.cc
@@ -22,9 +22,21 @@
   virtual Name
   queryRoutableName(const Name &name);
 
+  void
+  overridePrefix();
+
 };
 
-DummyTunnel::DummyTunnel() : CcnxTunnel() {m_localPrefix = Name("/local");}
+DummyTunnel::DummyTunnel() : CcnxTunnel()
+{
+  m_localPrefix = Name("/local");
+}
+
+void
+DummyTunnel::overridePrefix()
+{
+  CcnxWrapper::setInterestFilter(m_localPrefix, bind(&DummyTunnel::handleTunneledInterest, this, _1));
+}
 
 Name
 DummyTunnel::queryRoutableName (const Name &name)
@@ -36,9 +48,12 @@
 CcnxWrapperPtr t2(new DummyTunnel());
 CcnxWrapperPtr c1(new CcnxWrapper());
 
+DummyTunnel t3;
+
 // global data callback counter;
 int g_dc_i = 0;
 int g_dc_o = 0;
+int g_ic = 0;
 
 void innerCallback(const Name &name, const Bytes &content)
 {
@@ -52,7 +67,12 @@
   g_dc_o ++;
 }
 
-
+void interestCallback(const Name &name)
+{
+  string strName = name.toString();
+  t3.publishData(name, (const unsigned char *)strName.c_str(), strName.size(), 5);
+  g_ic++;
+}
 
 BOOST_AUTO_TEST_CASE (CcnxTunnelTest)
 {
@@ -79,5 +99,29 @@
 
 }
 
+BOOST_AUTO_TEST_CASE (CcnxTunnelRegister)
+{
+
+  g_ic = 0;
+  g_dc_i = 0;
+  t3.overridePrefix();
+  t3.setInterestFilter(Name("/t3"), bind(interestCallback, _1));
+  usleep(100000);
+  Closure *innerClosure = new Closure(1, bind(innerCallback, _1, _2));
+  t1->sendInterest(Name("/t3/hello"), innerClosure);
+  usleep(100000);
+  BOOST_CHECK_EQUAL(g_dc_i, 1);
+  BOOST_CHECK_EQUAL(g_ic, 1);
+
+  t3.clearInterestFilter(Name("/t3"));
+  usleep(100000);
+  t1->sendInterest(Name("/t3/hello-there"), innerClosure);
+  usleep(100000);
+  BOOST_CHECK_EQUAL(g_dc_i, 1);
+  BOOST_CHECK_EQUAL(g_ic, 1);
+  delete innerClosure;
+
+}
+
 
 BOOST_AUTO_TEST_SUITE_END()