ccnx tunnel; in progress
diff --git a/src/ccnx-tunnel.cpp b/src/ccnx-tunnel.cpp
new file mode 100644
index 0000000..2ac604a
--- /dev/null
+++ b/src/ccnx-tunnel.cpp
@@ -0,0 +1,94 @@
+#include "ccnx-tunnel.h"
+
+namespace Ccnx
+{
+
+CcnxTunnel::CcnxTunnel()
+                          : CcnxWrapper()
+                          , m_localPrefix("/")
+{
+  refreshLocalPrefix();
+}
+
+CcnxTunnel::~CcnxTunnel() 
+{
+}
+
+CcnxTunnel::refreshLocalPrefix() 
+{
+  string newPrefix = getLocalPrefix();
+  if (!newPrefix.empty() && m_localPrefix != newPrefix)
+  {
+    CcnxWrapper::clearInterestFilter(m_localPrefix);
+    CcnxWrapper::setInterestFilter(newPrefix, bind(&CcnxTunnel::handleTunneledInterest, this, _1));
+    m_localPrefix = newPrefix;
+  }
+}
+
+int
+CccnxTunnel::publishRawData(const string &name, const char *buf, size_t len, int freshness)
+{
+  ContentObjectPtr co = createContentObject(name, buf, len, freshness);
+  storeContentObject(name, co);
+  
+  string tunneledName = queryRoutableName(name);
+  ContentObjectPtr tunneledCo = createContentObject(tunneledName, co->m_data, co->m_len, freshness);
+
+  return putToCcnd(tunneledCo);
+}
+
+void
+CcnxTunnel::handleTunneledInterest(string tunneledInterest)
+{
+  // The interest must have m_localPrefix as a prefix (component-wise), otherwise ccnd would not deliver it to us
+  string interest = (m_localPrefix == "/") 
+                    ? tunneledInterest
+                    : tunneldInterest.substr(m_localPrefix.size());
+
+  ReadLock(m_ritLock); 
+  
+  // This is linear scan, but should be acceptable under the assumption that the caller wouldn't be listening to a lot prefixes (as of now, most app listen to one or two prefixes)
+  for (RitIter it = m_rit.begin(); it != m_rit.end(); it++)
+  {
+    // evoke callback for any prefix that is the prefix of the interest
+    if (isPrefix(it->first(), interest))
+    {
+      (it->second())(interest);
+    }
+  }
+}
+
+bool
+CcnxTunnel::isPrefix(string &prefix, string &name)
+{
+  // prefix is literally prefix of name 
+  if (name.find(prefix) == 0)
+  {
+    // name and prefix are exactly the same, or the next character in name
+    // is '/'; in both case, prefix is the ccnx prefix of name (component-wise)
+    if (name.size() == prefix.size() || name.at(prefix.size()) == '/')
+    {
+      return true;
+    }
+  }
+  return false;
+}
+
+int 
+CcnxTunnel::setInterestFilter(const string &prefix, const InterestCallback &interestCallback)
+{
+  WriteLock(m_ritLock);
+  m_rit.insert(make_pair(prefix, new InterestCallback(interestCallback)));
+  return 0;
+}
+
+void 
+CcnxTunnel::clearInterestFilter(const string &prefix)
+{
+  WriteLock(m_ritLock);
+  // remove all
+  m_rit.erase(prefix);
+}
+
+}
+