routing: Add routable prefix support

Change-Id: I31c860adf7aa985b96063dbf5444f308e5ea0b21
diff --git a/src/sync-socket.cc b/src/sync-socket.cc
index 1188441..ca015de 100644
--- a/src/sync-socket.cc
+++ b/src/sync-socket.cc
@@ -30,9 +30,15 @@
 
 using ndn::shared_ptr;
 
+static const uint8_t ROUTING_PREFIX_SEPARATOR[2] = {0xF0, 0x2E};
+
+const Name SyncSocket::EMPTY_NAME = Name();
+
 SyncSocket::SyncSocket (const Name& syncPrefix,
-                        const ndn::Name& dataPrefix,
+                        const Name& dataPrefix,
                         uint64_t dataSession,
+                        bool withRoutingPrefix,
+                        const Name& routingPrefix, 
                         shared_ptr<Face> face,
                         const IdentityCertificate& myCertificate,
                         shared_ptr<SecRuleRelative> dataRule,
@@ -40,11 +46,19 @@
                         RemoveCallback rmCallback )
   : m_dataPrefix(dataPrefix)
   , m_dataSession(dataSession)
+  , m_withRoutingPrefix(false)
   , m_newDataCallback(dataCallback)
   , m_myCertificate(myCertificate)
   , m_face(face)
   , m_ioService(face->ioService())
 {
+  if(withRoutingPrefix && !routingPrefix.isPrefixOf(m_dataPrefix))
+    {
+      m_withRoutingPrefix = true;
+      m_routableDataPrefix.append(routingPrefix).append(ROUTING_PREFIX_SEPARATOR, 2).append(m_dataPrefix);
+    }
+
+
   if(static_cast<bool>(dataRule))
     {
       m_withSecurity = true;
@@ -81,30 +95,50 @@
   data->setFreshnessPeriod(1000*freshness);
 
   m_ioService->post(bind(&SyncSocket::publishDataInternal, this, 
-                         data, m_dataPrefix, m_dataSession, isCert));
+                         data, isCert));
 }
 
 void
-SyncSocket::publishDataInternal(shared_ptr<Data> data, const Name &prefix, uint64_t session, bool isCert)
+SyncSocket::publishDataInternal(shared_ptr<Data> data, bool isCert)
 {
-  uint64_t sequence = getNextSeq(prefix, session);
-  Name dataName = prefix;
-  dataName.append(boost::lexical_cast<string>(session)).append(boost::lexical_cast<string>(sequence));
+  Name dataPrefix = (m_withRoutingPrefix ? m_routableDataPrefix : m_dataPrefix);
+
+  uint64_t sequence = getNextSeq();
+
+  Name dataName;
+  dataName.append(m_dataPrefix)
+    .append(boost::lexical_cast<string>(m_dataSession))
+    .append(boost::lexical_cast<string>(sequence));
   if(isCert)
     dataName.append("INTRO-CERT");
   data->setName(dataName);
-
   m_keyChain.sign(*data, m_myCertificate.getName());
-  m_face->put(*data);
 
-  SeqNo s(session, sequence + 1);
+  if(m_withRoutingPrefix)
+    {
+      Name wrappedName;
+      wrappedName.append(m_routableDataPrefix)
+        .append(boost::lexical_cast<string>(m_dataSession))
+        .append(boost::lexical_cast<string>(sequence));
 
-  m_sequenceLog[prefix] = s;
-  m_syncLogic->addLocalNames (prefix, session, sequence);
+      Data wrappedData(wrappedName);
+      wrappedData.setContent(data->wireEncode());
+      m_keyChain.sign(wrappedData, m_myCertificate.getName());
+
+      m_face->put(wrappedData);
+    }
+  else
+    {
+      m_face->put(*data);
+    }
+
+  SeqNo s(m_dataSession, sequence + 1);
+  m_sequenceLog[dataPrefix] = s;
+  m_syncLogic->addLocalNames (dataPrefix, m_dataSession, sequence); // If DNS works, we should use pure m_dataprefix rather than the one with routing prefix.
 }
 
 void 
-SyncSocket::fetchData(const Name &prefix, const SeqNo &seq, const OnDataValidated& dataCallback, int retry)
+SyncSocket::fetchData(const Name& prefix, const SeqNo& seq, const OnDataValidated& dataCallback, int retry)
 {
   Name interestName = prefix;
   interestName.append(boost::lexical_cast<string>(seq.getSession())).append(boost::lexical_cast<string>(seq.getSeq()));
@@ -112,28 +146,50 @@
   ndn::Interest interest(interestName);
   interest.setMustBeFresh(true);
 
-  const OnDataValidated& onValidated = bind(&SyncSocket::onDataValidated, this, _1, interestName.size(), dataCallback);
+  m_face->expressInterest(interest, 
+                          bind(&SyncSocket::onData, this, _1, _2, dataCallback), 
+                          bind(&SyncSocket::onDataTimeout, this, _1, retry, dataCallback));
+
+}
+
+void
+SyncSocket::onData(const ndn::Interest& interest, Data& data, const OnDataValidated& dataCallback)
+{
+  bool encaped = false;
+
+  Name interestName = interest.getName();
+  Name::const_iterator it = interestName.begin();
+  Name::const_iterator end = interestName.end();
+
+  size_t offset = interestName.size();
+  for(; it != end; it++)
+    {
+      offset--;
+      if(it->toEscapedString() == "%F0.")
+        {
+          encaped = true;
+          break;
+        }
+    }
+
+  if(!encaped)
+    offset = interestName.size();
+
+  const OnDataValidated& onValidated = bind(&SyncSocket::onDataValidated, this, _1, offset, dataCallback);
   const OnDataValidationFailed& onValidationFailed = bind(&SyncSocket::onDataValidationFailed, this, _1, _2);
 
-  m_face->expressInterest(interest, 
-                          bind(&SyncSocket::onData, this, _1, _2, onValidated, onValidationFailed), 
-                          bind(&SyncSocket::onDataTimeout, this, _1, retry, onValidated, onValidationFailed));
-
+  if(encaped)
+    {
+      shared_ptr<Data> innerData = make_shared<Data>();
+      innerData->wireDecode(data.getContent().blockFromValue());
+      m_syncValidator->validate(*innerData, onValidated, onValidationFailed);
+    }
+  else
+    m_syncValidator->validate(data, onValidated, onValidationFailed);
 }
 
 void
-SyncSocket::onData(const ndn::Interest& interest, Data& data,
-                   const OnDataValidated& onValidated,
-                   const OnDataValidationFailed& onValidationFailed)
-{
-  m_syncValidator->validate(data, onValidated, onValidationFailed);
-}
-
-void
-SyncSocket::onDataTimeout(const ndn::Interest& interest, 
-                          int retry,
-                          const OnDataValidated& onValidated,
-                          const OnDataValidationFailed& onValidationFailed)
+SyncSocket::onDataTimeout(const ndn::Interest& interest, int retry, const OnDataValidated& dataCallback)
 {
   if(retry > 0)
     {
@@ -142,14 +198,12 @@
                                    this,
                                    _1,
                                    _2,
-                                   onValidated,
-                                   onValidationFailed),
+                                   dataCallback),
                               bind(&SyncSocket::onDataTimeout, 
                                    this,
                                    _1,
                                    retry - 1,
-                                   onValidated,
-                                   onValidationFailed));
+                                   dataCallback));
                               
     }
   else
@@ -161,7 +215,6 @@
                             size_t interestNameSize,
                             const OnDataValidated& onValidated)
 {
-  _LOG_DEBUG("--------------------" << data->getName());
   if(data->getName().size() > interestNameSize 
      && data->getName().get(interestNameSize).toEscapedString() == "INTRO-CERT")
     {
diff --git a/src/sync-socket.h b/src/sync-socket.h
index 19fac0d..8013635 100644
--- a/src/sync-socket.h
+++ b/src/sync-socket.h
@@ -49,24 +49,34 @@
   typedef ndn::function< void (const std::vector<MissingDataInfo> &, SyncSocket * ) > NewDataCallback;
   typedef ndn::function< void (const std::string &/*prefix*/ ) > RemoveCallback;
 
-  SyncSocket (const ndn::Name& syncPrefix, 
-              const ndn::Name& dataPrefix,
-              uint64_t dataSession,
-              ndn::shared_ptr<ndn::Face> face,
-              const ndn::IdentityCertificate& myCertificate,
-              ndn::shared_ptr<ndn::SecRuleRelative> dataRule,
-              NewDataCallback dataCallback, 
-              RemoveCallback rmCallback);
+  static const ndn::Name EMPTY_NAME;
 
-  ~SyncSocket ();
+  SyncSocket(const ndn::Name& syncPrefix, 
+             const ndn::Name& dataPrefix,
+             uint64_t dataSession,
+             bool withRoutingPrefix,
+             const ndn::Name& routingPrefix,
+             ndn::shared_ptr<ndn::Face> face,
+             const ndn::IdentityCertificate& myCertificate,
+             ndn::shared_ptr<ndn::SecRuleRelative> dataRule,
+             NewDataCallback dataCallback, 
+             RemoveCallback rmCallback);
+
+  ~SyncSocket();
 
   void
   publishData(const uint8_t* buf, size_t len, int freshness, bool isCert = false);
 
   void 
-  remove (const ndn::Name &prefix) 
+  leave() 
   { 
-    m_syncLogic->remove(prefix); 
+    m_syncLogic->remove(m_withRoutingPrefix ? m_routableDataPrefix : m_dataPrefix); 
+  }
+
+  void
+  remove(const ndn::Name& prefix)
+  {
+    m_syncLogic->remove(prefix);
   }
 
   void 
@@ -79,21 +89,22 @@
   }
 
   uint64_t
-  getNextSeq (const ndn::Name &prefix, uint64_t session)
+  getNextSeq()
   {
-    SequenceLog::iterator i = m_sequenceLog.find (prefix);
+    // If DNS works, we should use pure m_dataprefix rather than the one with routing prefix.
+    SequenceLog::iterator i = m_sequenceLog.find (m_withRoutingPrefix ? m_routableDataPrefix : m_dataPrefix);
     
     if (i != m_sequenceLog.end ())
       {
         SeqNo s = i->second;
-        if (s.getSession() == session)
+        if (s.getSession() == m_dataSession)
           return s.getSeq();
       }
     return 0;
   }
 
   SyncLogic &
-  getLogic () 
+  getLogic() 
   { 
     return *m_syncLogic; 
   }
@@ -142,10 +153,7 @@
   
 private:
   void
-  publishDataInternal(ndn::shared_ptr<ndn::Data> data, 
-                      const ndn::Name &prefix, 
-                      uint64_t session, 
-                      bool isCert);
+  publishDataInternal(ndn::shared_ptr<ndn::Data> data, bool isCert);
 
   void 
   passCallback(const std::vector<MissingDataInfo> &v) 
@@ -154,15 +162,11 @@
   }
 
   void
-  onData(const ndn::Interest& interest, ndn::Data& data,
-         const ndn::OnDataValidated& onValidated,
-         const ndn::OnDataValidationFailed& onValidationFailed);
+  onData(const ndn::Interest& interest, ndn::Data& data, const ndn::OnDataValidated& dataCallback);
 
   void
-  onDataTimeout(const ndn::Interest& interest, 
-                int retry,
-                const ndn::OnDataValidated& onValidated,
-                const ndn::OnDataValidationFailed& onValidationFailed);
+  onDataTimeout(const ndn::Interest& interest, int retry, const ndn::OnDataValidated& dataCallback);
+
 
   void
   onDataValidated(const ndn::shared_ptr<const ndn::Data>& data,
@@ -178,6 +182,8 @@
 
   ndn::Name m_dataPrefix;
   uint64_t m_dataSession;
+  ndn::Name m_routableDataPrefix;
+  bool m_withRoutingPrefix;
   NewDataCallback m_newDataCallback;
   SequenceLog m_sequenceLog;
   ndn::IdentityCertificate m_myCertificate;
diff --git a/tests/test-socket.cc b/tests/test-socket.cc
index 400e289..e25ef17 100644
--- a/tests/test-socket.cc
+++ b/tests/test-socket.cc
@@ -43,7 +43,7 @@
 INIT_LOGGER ("Test.AppSocket");
 
 #define PRINT 
-//std::cout << "Line: " << __LINE__ << std::endl;
+// std::cout << "Line: " << __LINE__ << std::endl;
 
 class TestSocketApp {
 public:
@@ -65,10 +65,10 @@
     data.insert(make_pair(name, str2));
   }
   
-  void setNum(const ndn::shared_ptr<const ndn::Data>& dataPacket) {
-    int n = dataPacket->getContent().value_size() / 4;
+  void setNum(const ndn::shared_ptr<const ndn::Data>& data) {
+    int n = data->getContent().value_size() / 4;
     uint32_t *numbers = new uint32_t [n];
-    memcpy(numbers, dataPacket->getContent().value(), dataPacket->getContent().value_size());
+    memcpy(numbers, data->getContent().value(), data->getContent().value_size());
     for (int i = 0; i < n; i++) {
       sum += numbers[i];
     }
@@ -160,14 +160,18 @@
   {
     _LOG_DEBUG ("s1");
 
-    m_s1 = ndn::make_shared<SyncSocket>("/let/us/sync",
-                                        "/irl.cs.ucla.edu",
-                                        0,
-                                        m_face1,
-                                        *m_id1,
-                                        m_rule,
-                                        bind(&TestSocketApp::fetchAll, &m_a1, _1, _2), 
-                                        bind(&TestSocketApp::pass, &m_a1, _1));
+    m_s1 = ndn::shared_ptr<SyncSocket>
+      (new SyncSocket("/let/us/sync",
+                      "/irl.cs.ucla.edu",
+                      0,
+                      false,
+                      "/",
+                      m_face1,
+                      *m_id1,
+                      m_rule,
+                      bind(&TestSocketApp::fetchAll, &m_a1, _1, _2), 
+                      bind(&TestSocketApp::pass, &m_a1, _1)));
+
     m_s1->addParticipant(*m_id2);
   }
 
@@ -176,14 +180,18 @@
   {
     _LOG_DEBUG ("s2");
 
-    m_s2 = ndn::make_shared<SyncSocket>("/let/us/sync",
-                                        "/yakshi.org",
-                                        0,
-                                        m_face2,
-                                        *m_id2,
-                                        m_rule,
-                                        bind(&TestSocketApp::fetchAll, &m_a2, _1, _2), 
-                                        bind(&TestSocketApp::pass, &m_a2, _1));
+    m_s2 = ndn::shared_ptr<SyncSocket>
+      (new SyncSocket("/let/us/sync",
+                      "/yakshi.org",
+                      0,
+                      false,
+                      "/",
+                      m_face2,
+                      *m_id2,
+                      m_rule,
+                      bind(&TestSocketApp::fetchAll, &m_a2, _1, _2), 
+                      bind(&TestSocketApp::pass, &m_a2, _1)));
+
     m_s2->addParticipant(*m_id1);
     m_s2->addParticipant(*m_id3);
   }
@@ -193,14 +201,18 @@
   {
     _LOG_DEBUG ("s3");
 
-    m_s3 = ndn::make_shared<SyncSocket>("/let/us/sync",
-                                        "/google.com",
-                                        0,
-                                        m_face3,
-                                        *m_id3,
-                                        m_rule,  
-                                        bind(&TestSocketApp::fetchAll, &m_a3, _1, _2), 
-                                        bind(&TestSocketApp::pass, &m_a3, _1));
+    m_s3 = ndn::shared_ptr<SyncSocket>
+      (new SyncSocket("/let/us/sync",
+                      "/google.com",
+                      0,
+                      false,
+                      "/",
+                      m_face3,
+                      *m_id3,
+                      m_rule,  
+                      bind(&TestSocketApp::fetchAll, &m_a3, _1, _2), 
+                      bind(&TestSocketApp::pass, &m_a3, _1)));
+
     m_s3->addParticipant(*m_id2);
   }
 
@@ -303,14 +315,17 @@
   {
     _LOG_DEBUG ("s1");
     
-    m_s1 = ndn::make_shared<SyncSocket>("/this/is/the/prefix",
-                                        "/xiaonei.com",
-                                        0,
-                                        m_face1,
-                                        *m_id1,
-                                        m_rule,
-                                        bind(&TestSocketApp::fetchNumbers, &m_a1, _1, _2), 
-                                        bind(&TestSocketApp::pass, &m_a1, _1));
+    m_s1 = ndn::shared_ptr<SyncSocket>
+      (new SyncSocket("/this/is/the/prefix",
+                      "/xiaonei.com",
+                      0,
+                      false,
+                      "/",                                        
+                      m_face1,
+                      *m_id1,
+                      m_rule,
+                      bind(&TestSocketApp::fetchNumbers, &m_a1, _1, _2), 
+                      bind(&TestSocketApp::pass, &m_a1, _1)));
 
     m_s1->addParticipant(*m_id2);
   }
@@ -320,14 +335,133 @@
   {
     _LOG_DEBUG ("s2");
 
-    m_s2 = ndn::make_shared<SyncSocket>("/this/is/the/prefix",
-                                        "/mitbbs.com",
-                                        0,
-                                        m_face2,
-                                        *m_id2,
-                                        m_rule,
-                                        bind(&TestSocketApp::fetchNumbers, &m_a2, _1, _2), 
-                                        bind(&TestSocketApp::pass, &m_a2, _1));
+    m_s2 = ndn::shared_ptr<SyncSocket>
+      (new SyncSocket("/this/is/the/prefix",
+                      "/mitbbs.com",
+                      0,
+                      false,
+                      "/",
+                      m_face2,
+                      *m_id2,
+                      m_rule,
+                      bind(&TestSocketApp::fetchNumbers, &m_a2, _1, _2), 
+                      bind(&TestSocketApp::pass, &m_a2, _1)));
+
+    m_s2->addParticipant(*m_id1);
+  }
+  
+  void
+  publishSocket1(string data)
+  {
+    _LOG_DEBUG ("s1 publish");
+    m_s1->publishData (reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), 1000); 
+  }
+
+  void
+  publishSocket2(string data)
+  {
+    _LOG_DEBUG ("s2 publish");
+    m_s2->publishData (reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), 1000); 
+  }
+
+  void
+  setSocket1(const char* ptr, size_t size)
+  {
+    _LOG_DEBUG ("a1 setNum");
+    m_a1.setNum ("/xiaonei.com", ptr, size); 
+  }
+
+  void
+  setSocket2(const char* ptr, size_t size)
+  {
+    _LOG_DEBUG ("a2 setNum");
+    m_a2.setNum ("/mitbbs.com", ptr, size); 
+  }
+
+  void
+  check(int num)
+  { 
+    _LOG_DEBUG ("codnum " << num);
+    _LOG_DEBUG ("a1 sum " << m_a1.sum);
+    _LOG_DEBUG ("a2 sum " << m_a2.sum);
+
+    BOOST_CHECK(m_a1.sum == m_a2.sum && m_a1.sum == num);
+  }
+
+  void
+  done()
+  {
+    m_s1.reset();
+    m_s2.reset();
+
+    m_keyChain.deleteIdentity(m_name1);
+    m_keyChain.deleteIdentity(m_name2);
+  }
+
+  ndn::KeyChain m_keyChain;
+  ndn::shared_ptr<ndn::SecRuleRelative> m_rule;
+
+  TestSocketApp m_a1, m_a2;
+  ndn::shared_ptr<ndn::IdentityCertificate> m_id1, m_id2;
+  ndn::shared_ptr<ndn::Face> m_face1, m_face2;
+  ndn::Name m_name1, m_name2;
+  ndn::shared_ptr<SyncSocket> m_s1, m_s2;
+};
+
+
+
+class TestSet3{
+public:
+  TestSet3(ndn::shared_ptr<boost::asio::io_service> ioService)
+    : m_face1(new ndn::Face(ioService))
+    , m_face2(new ndn::Face(ioService))
+    , m_name1("/xiaonei.com/" + boost::lexical_cast<std::string>(ndn::time::now()))
+    , m_name2("/mitbbs.com/" + boost::lexical_cast<std::string>(ndn::time::now()))
+  {
+    m_id1 = m_keyChain.getCertificate(m_keyChain.createIdentity(m_name1));
+    m_id2 = m_keyChain.getCertificate(m_keyChain.createIdentity(m_name2));
+
+    m_rule = ndn::make_shared<ndn::SecRuleRelative>("^(<>*)<><>$",
+                                                    "^(<>*)<><KEY><ksk-.*><ID-CERT>$",
+                                                    "==", "\\1", "\\1", true);
+  }
+
+  void
+  createSyncSocket1()
+  {
+    _LOG_DEBUG ("s1");
+    
+    m_s1 = ndn::shared_ptr<SyncSocket>
+      (new SyncSocket("/this/is/the/prefix",
+                      "/xiaonei.com",
+                      1,
+                      true,
+                      "/abc",                                        
+                      m_face1,
+                      *m_id1,
+                      m_rule,
+                      bind(&TestSocketApp::fetchNumbers, &m_a1, _1, _2), 
+                      bind(&TestSocketApp::pass, &m_a1, _1)));
+
+    m_s1->addParticipant(*m_id2);
+  }
+
+  void
+  createSyncSocket2()
+  {
+    _LOG_DEBUG ("s2");
+
+    m_s2 = ndn::shared_ptr<SyncSocket>
+      (new SyncSocket("/this/is/the/prefix",
+                      "/mitbbs.com",
+                      1,
+                      false,
+                      "/",
+                      m_face2,
+                      *m_id2,
+                      m_rule,
+                      bind(&TestSocketApp::fetchNumbers, &m_a2, _1, _2), 
+                      bind(&TestSocketApp::pass, &m_a2, _1)));
 
     m_s2->addParticipant(*m_id1);
   }
@@ -458,3 +592,26 @@
 
   ioService->run();
 }
+
+BOOST_AUTO_TEST_CASE (AppSocketTest3)
+{
+  ndn::shared_ptr<boost::asio::io_service> ioService = ndn::make_shared<boost::asio::io_service>();
+  ndn::Scheduler scheduler(*ioService);
+  TestSet3 testSet3(ioService);
+
+  scheduler.scheduleEvent(ndn::time::seconds(0.00), ndn::bind(&TestSet3::createSyncSocket1, &testSet3));
+  scheduler.scheduleEvent(ndn::time::seconds(0.20), ndn::bind(&TestSet3::createSyncSocket2, &testSet3));
+  uint32_t num[5] = {0, 1, 2, 3, 4};
+  string data0((const char *) num, sizeof(num));
+  scheduler.scheduleEvent(ndn::time::seconds(1.00), ndn::bind(&TestSet3::publishSocket1, &testSet3, data0));
+  scheduler.scheduleEvent(ndn::time::seconds(1.50), ndn::bind(&TestSet3::setSocket1, &testSet3, (const char *) num, sizeof (num)));
+  scheduler.scheduleEvent(ndn::time::seconds(2.00), ndn::bind(&TestSet3::check, &testSet3, 10));
+  uint32_t newNum[5] = {9, 7, 2, 1, 1};
+  string data1((const char *) newNum, sizeof(newNum));
+  scheduler.scheduleEvent(ndn::time::seconds(3.00), ndn::bind(&TestSet3::publishSocket2, &testSet3, data1));
+  scheduler.scheduleEvent(ndn::time::seconds(3.50), ndn::bind(&TestSet3::setSocket2, &testSet3, (const char *) newNum, sizeof (newNum)));
+  scheduler.scheduleEvent(ndn::time::seconds(5.00), ndn::bind(&TestSet3::check, &testSet3, 30));
+  scheduler.scheduleEvent(ndn::time::seconds(7.00), ndn::bind(&TestSet3::done, &testSet3));
+
+  ioService->run();
+}