forked from cawka/ndn.cxx
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..016660a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2013, Regents of the University of California
+Copyright (c) 2013, Alexander Afanasyev
+Copyright (c) 2013, Zhenkai Zhu
+
+All rights reserved.
+Written by: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ Zhenkai Zhu <zhenkai@cs.ucla.edu>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the Regents of the University of California nor
+ the names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL REGENTS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
index 3a3792a..ffb0947 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,43 @@
-ndn-cpp
-=======
+NDN.cxx: C++ NDN API (using CCNx C Library)
+===========================================
-c++ bindings for NDN
+People often feel confusing and tedious when using CCNx C library, and this is an attempt to make it easier to program NDN applications using C++.
+
+This API remotely resembles PyCCN API if you by any chance have already got yourself familiar with that.
+
+The functions included are be roughly devided into two categories: NDN operations and async operations.
+
+1. NDN Operations
+------------------
+This is a set of functions that provide relative easier ways to perform NDN operations, including manipulating NDN names, content objects, interests, sending interests, callbacks (closure) for content objects, name prefix discovery, signature verifications, etc.. There is also a blocking API to fetch content object.
+
+2. Async Operations
+-------------------
+Communications in NDN is mostly async. There is an event thread running NDN and processing the NDN events (e.g. interests received, expired, content received, etc..). As such, you don't really want to do a lot of processing in the NDN event thread (which blocks processing of that events). Hence we provide a simple executor API, which allows you to process the events in separate threads. We also provide a scheduler which allows you to scheduler various events as you wish. The scheduler is based on libevent C API.
+
+3. Build and Install
+--------------------
+To see more options, use `./waf configure --help`.
+For default install, use
+```bash
+./waf configure
+./waf
+sudo ./waf install
+```
+
+### If you're using Mac OS X, Macport's g++ is not recommended. It may cause mysterious memory error with tinyxml. Use clang++ or Apple's g++ instead.
+
+Normally, default install goes to /usr/local.
+If you have added /usr/local/lib/pkgconfig to your `PKG_CONFIG_PATH`, then you can compile your code like this:
+```bash
+g++ code.cpp `pkg-config --cflags --libs libndn.cxx`
+```
+
+4. Examples
+-----------
+
+example/ directory contains a fully working example of simple client and server applications written using NDN.cxx API.
+
+There is also an extensive usage of this library in [ChronoShare](https://github.com/named-data/ChronoShare).
+
+
diff --git a/disabled/cert.cc b/disabled/cert.cc
new file mode 100644
index 0000000..b8a170e
--- /dev/null
+++ b/disabled/cert.cc
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 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>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+#include "cert.h"
+
+#include <tinyxml.h>
+#include <boost/lexical_cast.hpp>
+
+#include "logging.h"
+
+INIT_LOGGER ("ndn.Cert");
+
+using namespace std;
+
+namespace ndn {
+
+Cert::Cert()
+ : m_pkey(0)
+ , m_meta("", "", 0, 0)
+{
+}
+
+Cert::Cert(const PcoPtr &keyObject, const PcoPtr &metaObject = PcoPtr())
+ : m_pkey(0)
+ , m_meta("", "", 0, 0)
+{
+ m_name = keyObject->name();
+ m_rawKeyBytes = keyObject->content();
+ m_keyHash = *(Hash::FromBytes(m_rawKeyBytes));
+ m_pkey = ccn_d2i_pubkey(head(m_rawKeyBytes), m_rawKeyBytes.size());
+ updateMeta(metaObject);
+}
+
+Cert::~Cert()
+{
+ if (m_pkey != 0)
+ {
+ ccn_pubkey_free(m_pkey);
+ m_pkey = 0;
+ }
+}
+
+void
+Cert::updateMeta(const PcoPtr &metaObject)
+{
+ if (metaObject)
+ {
+ Bytes xml = metaObject->content();
+ // just make sure it's null terminated as it's required by TiXmlDocument::parse
+ xml.push_back('\0');
+ TiXmlDocument doc;
+ doc.Parse((const char *)(head(xml)));
+ if (!doc.Error())
+ {
+ TiXmlElement *root = doc.RootElement();
+ for (TiXmlElement *child = root->FirstChildElement(); child; child = child->NextSiblingElement())
+ {
+ string elemName = child->Value();
+ string text = child->GetText();
+ if (elemName == "Name")
+ {
+ m_meta.realworldID = text;
+ _LOG_TRACE("Name = " << text);
+ }
+ else if (elemName == "Affiliation")
+ {
+ m_meta.affiliation = text;
+ _LOG_TRACE("Affiliation = " << text);
+ }
+ else if (elemName == "Valid_to")
+ {
+ m_meta.validTo = boost::lexical_cast<time_t>(text);
+ _LOG_TRACE("Valid_to = " << text);
+ }
+ else if (elemName == "Valid_from")
+ {
+ // this is not included in the key meta yet
+ // but it should eventually be there
+ }
+ else
+ {
+ // ignore known stuff
+ }
+ }
+ }
+ else
+ {
+ _LOG_ERROR("Cannot parse meta info:" << std::string((const char *)head(xml), xml.size()));
+ }
+ }
+}
+
+Cert::VALIDITY
+Cert::validity()
+{
+ if (m_meta.validFrom == 0 && m_meta.validTo == 0)
+ {
+ return OTHER;
+ }
+
+ time_t now = time(NULL);
+ if (now < m_meta.validFrom)
+ {
+ return NOT_YET_VALID;
+ }
+
+ if (now >= m_meta.validTo)
+ {
+ return EXPIRED;
+ }
+
+ return WITHIN_VALID_TIME_SPAN;
+}
+
+} // ndn
diff --git a/disabled/cert.h b/disabled/cert.h
new file mode 100644
index 0000000..00f432d
--- /dev/null
+++ b/disabled/cert.h
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 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>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_CERT_H
+#define NDN_CERT_H
+
+#include "ndn.cxx/common.h"
+#include "ndn.cxx/name.h"
+#include "ndn.cxx/pco.h"
+#include "ndn.cxx/hash.h"
+#include <boost/shared_ptr.hpp>
+
+namespace ndn {
+
+class Cert
+{
+public:
+ enum VALIDITY
+ {
+ NOT_YET_VALID,
+ WITHIN_VALID_TIME_SPAN,
+ EXPIRED,
+ OTHER
+ };
+
+ Cert();
+ Cert(const PcoPtr &keyObject, const PcoPtr &metaObject);
+ ~Cert();
+
+ void
+ updateMeta(const PcoPtr &metaObject);
+
+ Name
+ name() { return m_name; }
+
+ Bytes
+ rawKeyBytes() { return m_rawKeyBytes; }
+
+ Hash
+ keyDigest() { return m_keyHash; }
+
+ std::string
+ realworldID() { return m_meta.realworldID; }
+
+ std::string
+ affilication() { return m_meta.affiliation; }
+
+ ccn_pkey *
+ pkey() { return m_pkey; }
+
+ VALIDITY
+ validity();
+
+private:
+ struct Meta
+ {
+ Meta(std::string id, std::string affi, time_t from, time_t to)
+ : realworldID(id)
+ , affiliation(affi)
+ , validFrom(from)
+ , validTo(to)
+ {
+ }
+ std::string realworldID;
+ std::string affiliation;
+ time_t validFrom;
+ time_t validTo;
+ };
+
+ Name m_name;
+ Hash m_keyHash; // publisherPublicKeyHash
+ Bytes m_rawKeyBytes;
+ ccn_pkey *m_pkey;
+ Meta m_meta;
+};
+
+typedef boost::shared_ptr<Cert> CertPtr;
+
+}
+
+#endif // NDN_CERT_H
diff --git a/disabled/charbuf.cc b/disabled/charbuf.cc
new file mode 100644
index 0000000..12425f6
--- /dev/null
+++ b/disabled/charbuf.cc
@@ -0,0 +1,79 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "charbuf.h"
+
+using namespace std;
+
+namespace ndn {
+
+void
+Charbuf::init(ccn_charbuf *buf)
+{
+ if (buf != NULL)
+ {
+ m_buf = ccn_charbuf_create();
+ ccn_charbuf_reserve(m_buf, buf->length);
+ memcpy(m_buf->buf, buf->buf, buf->length);
+ m_buf->length = buf->length;
+ }
+}
+
+Charbuf::Charbuf()
+ : m_buf(NULL)
+{
+ m_buf = ccn_charbuf_create();
+}
+
+Charbuf::Charbuf(ccn_charbuf *buf)
+ : m_buf(NULL)
+{
+ init(buf);
+}
+
+Charbuf::Charbuf(const Charbuf &other)
+ : m_buf (NULL)
+{
+ init(other.m_buf);
+}
+
+Charbuf::Charbuf(const void *buf, size_t length)
+{
+ m_buf = ccn_charbuf_create ();
+ ccn_charbuf_reserve (m_buf, length);
+ memcpy (m_buf->buf, buf, length);
+ m_buf->length = length;
+}
+
+Charbuf::~Charbuf()
+{
+ ccn_charbuf_destroy (&m_buf);
+}
+
+namespace iostreams
+{
+
+charbuf_append_device::charbuf_append_device (Charbuf& cnt)
+ : container (cnt)
+{
+}
+
+std::streamsize
+charbuf_append_device::write (const char_type* s, std::streamsize n)
+{
+ ccn_charbuf_append (container.getBuf (), s, n);
+ return n;
+}
+
+} // iostreams
+
+} // ndn
diff --git a/disabled/charbuf.h b/disabled/charbuf.h
new file mode 100644
index 0000000..ce3ddef
--- /dev/null
+++ b/disabled/charbuf.h
@@ -0,0 +1,100 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_NDN_CHARBUF_H
+#define NDN_NDN_CHARBUF_H
+
+#include "ndn.cxx/common.h"
+#include <boost/shared_ptr.hpp>
+#include <boost/iostreams/detail/ios.hpp>
+#include <boost/iostreams/categories.hpp>
+#include <boost/iostreams/stream.hpp>
+
+namespace ndn {
+
+class Charbuf;
+typedef boost::shared_ptr<Charbuf> CharbufPtr;
+
+// This class is mostly used in Wrapper; users should not be directly using this class
+// The main purpose of this class to is avoid manually create and destroy charbuf everytime
+class Charbuf
+{
+public:
+ Charbuf();
+ Charbuf(ccn_charbuf *buf);
+ Charbuf(const Charbuf &other);
+ Charbuf(const void *buf, size_t length);
+ ~Charbuf();
+
+ // expose internal data structure, use with caution!!
+ ccn_charbuf *
+ getBuf() { return m_buf; }
+
+ const ccn_charbuf *
+ getBuf() const { return m_buf; }
+
+ const unsigned char *
+ buf () const
+ { return m_buf->buf; }
+
+ size_t
+ length () const
+ { return m_buf->length; }
+
+private:
+ void init(ccn_charbuf *buf);
+
+protected:
+ ccn_charbuf *m_buf;
+};
+
+namespace iostreams
+{
+
+class charbuf_append_device {
+public:
+ typedef char char_type;
+ typedef boost::iostreams::sink_tag category;
+
+ charbuf_append_device (Charbuf& cnt);
+
+ std::streamsize
+ write(const char_type* s, std::streamsize n);
+protected:
+ Charbuf& container;
+};
+
+} // iostreams
+
+struct charbuf_stream : public boost::iostreams::stream<iostreams::charbuf_append_device>
+{
+ charbuf_stream ()
+ : m_device (m_buf)
+ {
+ open (m_device);
+ }
+
+ Charbuf &
+ buf ()
+ {
+ flush ();
+ return m_buf;
+ }
+
+private:
+ Charbuf m_buf;
+ iostreams::charbuf_append_device m_device;
+};
+
+} // ndn
+
+#endif // NDN_NDN_CHARBUF_H
diff --git a/disabled/closure.cc b/disabled/closure.cc
new file mode 100644
index 0000000..a45ef2a
--- /dev/null
+++ b/disabled/closure.cc
@@ -0,0 +1,46 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "closure.h"
+
+namespace ndn {
+
+Closure::Closure(const DataCallback &dataCallback, const TimeoutCallback &timeoutCallback)
+ : m_timeoutCallback (timeoutCallback)
+ , m_dataCallback (dataCallback)
+{
+}
+
+Closure::~Closure ()
+{
+}
+
+void
+Closure::runTimeoutCallback(Name interest, const Closure &closure, InterestPtr origInterest)
+{
+ if (!m_timeoutCallback.empty ())
+ {
+ m_timeoutCallback (interest, closure, origInterest);
+ }
+}
+
+
+void
+Closure::runDataCallback(Name name, PcoPtr content)
+{
+ if (!m_dataCallback.empty ())
+ {
+ m_dataCallback (name, content);
+ }
+}
+
+} // ndn
diff --git a/disabled/closure.h b/disabled/closure.h
new file mode 100644
index 0000000..dbcba79
--- /dev/null
+++ b/disabled/closure.h
@@ -0,0 +1,51 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_CLOSURE_H
+#define NDN_CLOSURE_H
+
+#include "ndn.cxx/common.h"
+#include "ndn.cxx/fields/name.h"
+#include "ndn.cxx/interest.h"
+
+namespace ndn {
+
+class ParsedContentObject;
+typedef boost::shared_ptr<ParsedContentObject> PcoPtr;
+
+class Closure
+{
+public:
+ typedef boost::function<void (Name, PcoPtr pco)> DataCallback;
+
+ typedef boost::function<void (Name, const Closure &, InterestPtr)> TimeoutCallback;
+
+ Closure(const DataCallback &dataCallback, const TimeoutCallback &timeoutCallback = TimeoutCallback());
+ virtual ~Closure();
+
+ virtual void
+ runDataCallback(Name name, ndn::PcoPtr pco);
+
+ virtual void
+ runTimeoutCallback(Name interest, const Closure &closure, InterestPtr originalInterest);
+
+ virtual Closure *
+ dup () const { return new Closure (*this); }
+
+public:
+ TimeoutCallback m_timeoutCallback;
+ DataCallback m_dataCallback;
+};
+
+} // ndn
+
+#endif
diff --git a/disabled/discovery.cc b/disabled/discovery.cc
new file mode 100644
index 0000000..273402a
--- /dev/null
+++ b/disabled/discovery.cc
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 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>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "discovery.h"
+
+#include "scheduler/scheduler.h"
+#include "scheduler/simple-interval-generator.h"
+#include "scheduler/task.h"
+#include "scheduler/periodic-task.h"
+
+#include <sstream>
+#include <boost/make_shared.hpp>
+#include <boost/bind.hpp>
+
+using namespace std;
+
+namespace ndn
+{
+
+namespace discovery
+{
+
+const string
+TaggedFunction::CHAR_SET = string("abcdefghijklmnopqtrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
+
+TaggedFunction::TaggedFunction(const Callback &callback, const string &tag)
+ : m_callback(callback)
+ , m_tag(tag)
+{
+}
+
+string
+TaggedFunction::GetRandomTag()
+{
+ //boost::random::random_device rng;
+ boost::random::uniform_int_distribution<> dist(0, CHAR_SET.size() - 1);
+ ostringstream oss;
+ for (int i = 0; i < DEFAULT_TAG_SIZE; i++)
+ {
+ //oss << CHAR_SET[dist(rng)];
+ }
+ return oss.str();
+}
+
+void
+TaggedFunction::operator()(const Name &name)
+{
+ if (!m_callback.empty())
+ {
+ m_callback(name);
+ }
+}
+
+} // namespace discovery
+
+const double
+Discovery::INTERVAL = 15.0;
+
+Discovery *
+Discovery::instance = NULL;
+
+boost::mutex
+Discovery::mutex;
+
+Discovery::Discovery()
+ : m_scheduler(new Scheduler())
+ , m_localPrefix("/")
+{
+ m_scheduler->start();
+
+ Scheduler::scheduleOneTimeTask (m_scheduler, 0,
+ boost::bind(&Discovery::poll, this), "Initial-Local-Prefix-Check");
+ Scheduler::schedulePeriodicTask (m_scheduler,
+ boost::make_shared<SimpleIntervalGenerator>(INTERVAL),
+ boost::bind(&Discovery::poll, this), "Local-Prefix-Check");
+}
+
+Discovery::~Discovery()
+{
+ m_scheduler->shutdown();
+}
+
+void
+Discovery::addCallback(const discovery::TaggedFunction &callback)
+{
+ m_callbacks.push_back(callback);
+}
+
+int
+Discovery::deleteCallback(const discovery::TaggedFunction &callback)
+{
+ List::iterator it = m_callbacks.begin();
+ while (it != m_callbacks.end())
+ {
+ if ((*it) == callback)
+ {
+ it = m_callbacks.erase(it);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+ return m_callbacks.size();
+}
+
+void
+Discovery::poll()
+{
+ Name localPrefix = Wrapper::getLocalPrefix();
+ if (localPrefix != m_localPrefix)
+ {
+ Lock lock(mutex);
+ for (List::iterator it = m_callbacks.begin(); it != m_callbacks.end(); ++it)
+ {
+ (*it)(localPrefix);
+ }
+ m_localPrefix = localPrefix;
+ }
+}
+
+void
+Discovery::registerCallback(const discovery::TaggedFunction &callback)
+{
+ Lock lock(mutex);
+ if (instance == NULL)
+ {
+ instance = new Discovery();
+ }
+
+ instance->addCallback(callback);
+}
+
+void
+Discovery::deregisterCallback(const discovery::TaggedFunction &callback)
+{
+ Lock lock(mutex);
+ if (instance == NULL)
+ {
+ cerr << "Discovery::deregisterCallback called without instance" << endl;
+ }
+ else
+ {
+ int size = instance->deleteCallback(callback);
+ if (size == 0)
+ {
+ delete instance;
+ instance = NULL;
+ }
+ }
+}
+
+}
+
diff --git a/disabled/discovery.h b/disabled/discovery.h
new file mode 100644
index 0000000..1dc684d
--- /dev/null
+++ b/disabled/discovery.h
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 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>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_DISCOVERY_H
+#define NDN_DISCOVERY_H
+
+#include "ndn.cxx/wrapper.h"
+#include "ndn.cxx/common.h"
+#include "ndn.cxx/name.h"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <boost/random/random_device.hpp>
+#include <boost/random/uniform_int_distribution.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/locks.hpp>
+#include <list>
+
+class Scheduler;
+typedef boost::shared_ptr<Scheduler> SchedulerPtr;
+
+namespace ndn
+{
+
+class Discovery;
+typedef boost::shared_ptr<Discovery> DiscoveryPtr;
+
+namespace discovery
+{
+
+class TaggedFunction
+{
+public:
+ typedef boost::function<void (const Name &)> Callback;
+ TaggedFunction(const Callback &callback, const std::string &tag = GetRandomTag());
+ ~TaggedFunction(){};
+
+ bool
+ operator==(const TaggedFunction &other) { return m_tag == other.m_tag; }
+
+ void
+ operator()(const Name &name);
+
+private:
+ static const std::string CHAR_SET;
+ static const int DEFAULT_TAG_SIZE = 32;
+
+ static std::string
+ GetRandomTag();
+
+private:
+ Callback m_callback;
+ std::string m_tag;
+};
+
+}
+
+class Discovery
+{
+public:
+ const static double INTERVAL;
+ // Add a callback to be invoked when local prefix changes
+ // you must remember to deregister the callback
+ // otherwise you may have undefined behavior if the callback is
+ // bind to a member function of an object and the object is deleted
+ static void
+ registerCallback(const discovery::TaggedFunction &callback);
+
+ // remember to call this before you quit
+ static void
+ deregisterCallback(const discovery::TaggedFunction &callback);
+
+private:
+ Discovery();
+ ~Discovery();
+
+ void
+ poll();
+
+ void
+ addCallback(const discovery::TaggedFunction &callback);
+
+ int
+ deleteCallback(const discovery::TaggedFunction &callback);
+
+private:
+ typedef boost::mutex Mutex;
+ typedef boost::unique_lock<Mutex> Lock;
+ typedef std::list<discovery::TaggedFunction> List;
+
+ static Discovery *instance;
+ static Mutex mutex;
+ List m_callbacks;
+ SchedulerPtr m_scheduler;
+ Name m_localPrefix;
+};
+
+} // ndn
+
+#endif // NDN_DISCOVERY_H
diff --git a/disabled/pco.cc b/disabled/pco.cc
new file mode 100644
index 0000000..f039b54
--- /dev/null
+++ b/disabled/pco.cc
@@ -0,0 +1,138 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "pco.h"
+
+namespace ndn {
+
+void
+ParsedContentObject::init(const unsigned char *data, size_t len)
+{
+ readRaw(m_bytes, data, len);
+
+ m_comps = ccn_indexbuf_create();
+ int res = ccn_parse_ContentObject(head (m_bytes), len, &m_pco, m_comps);
+ if (res < 0)
+ {
+ boost::throw_exception(Error::MisformedContentObject());
+ }
+
+}
+
+ParsedContentObject::ParsedContentObject(const unsigned char *data, size_t len, bool verified)
+ : m_comps(NULL)
+ , m_verified(verified)
+{
+ init(data, len);
+}
+
+ParsedContentObject::ParsedContentObject(const Bytes &bytes, bool verified)
+ : m_comps(NULL)
+ , m_verified(verified)
+{
+ init(head(bytes), bytes.size());
+}
+
+ParsedContentObject::ParsedContentObject(const ParsedContentObject &other, bool verified)
+ : m_comps(NULL)
+ , m_verified(verified)
+{
+ init(head(other.m_bytes), other.m_bytes.size());
+}
+
+ParsedContentObject::~ParsedContentObject()
+{
+ ccn_indexbuf_destroy(&m_comps);
+ m_comps = NULL;
+}
+
+Bytes
+ParsedContentObject::content() const
+{
+ const unsigned char *content;
+ size_t len;
+ int res = ccn_content_get_value(head(m_bytes), m_pco.offset[CCN_PCO_E], &m_pco, &content, &len);
+ if (res < 0)
+ {
+ boost::throw_exception(Error::MisformedContentObject());
+ }
+
+ Bytes bytes;
+ readRaw(bytes, content, len);
+ return bytes;
+}
+
+BytesPtr
+ParsedContentObject::contentPtr() const
+{
+ const unsigned char *content;
+ size_t len;
+ int res = ccn_content_get_value(head(m_bytes), m_pco.offset[CCN_PCO_E], &m_pco, &content, &len);
+ if (res < 0)
+ {
+ boost::throw_exception(Error::MisformedContentObject());
+ }
+
+ return readRawPtr (content, len);
+}
+
+Name
+ParsedContentObject::name() const
+{
+ return Name(head(m_bytes), m_comps);
+}
+
+Name
+ParsedContentObject::keyName() const
+{
+ if (m_pco.offset[CCN_PCO_E_KeyName_Name] > m_pco.offset[CCN_PCO_B_KeyName_Name])
+ {
+ CharbufPtr ptr = boost::make_shared<Charbuf>();
+ ccn_charbuf_append(ptr->getBuf(), head(m_bytes) + m_pco.offset[CCN_PCO_B_KeyName_Name], m_pco.offset[CCN_PCO_E_KeyName_Name] - m_pco.offset[CCN_PCO_B_KeyName_Name]);
+
+ return Name(*ptr);
+ }
+ else
+ {
+ return Name();
+ }
+}
+
+HashPtr
+ParsedContentObject::publisherPublicKeyDigest() const
+{
+ const unsigned char *buf = NULL;
+ size_t size = 0;
+ ccn_ref_tagged_BLOB(CCN_DTAG_PublisherPublicKeyDigest, head(m_bytes), m_pco.offset[CCN_PCO_B_PublisherPublicKeyDigest], m_pco.offset[CCN_PCO_E_PublisherPublicKeyDigest], &buf, &size);
+
+ return boost::make_shared<Hash>(buf, size);
+}
+
+ParsedContentObject::Type
+ParsedContentObject::type() const
+{
+ switch (m_pco.type)
+ {
+ case CCN_CONTENT_DATA: return DATA;
+ case CCN_CONTENT_KEY: return KEY;
+ default: break;
+ }
+ return OTHER;
+}
+
+// void
+// ParsedContentObject::verifySignature(const CertPtr &cert)
+// {
+// m_verified = (ccn_verify_signature(head(m_bytes), m_pco.offset[CCN_PCO_E], &m_pco, cert->pkey()) == 1);
+// }
+
+}
diff --git a/disabled/pco.h b/disabled/pco.h
new file mode 100644
index 0000000..6931022
--- /dev/null
+++ b/disabled/pco.h
@@ -0,0 +1,101 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_CONTENT_OBJECT_H
+#define NDN_CONTENT_OBJECT_H
+
+#include "ndn.cxx/wrapper.h"
+#include "ndn.cxx/common.h"
+#include "ndn.cxx/fields/name.h"
+#include "ndn.cxx/helpers/hash.h"
+
+namespace ndn {
+
+// class Cert;
+// typedef boost::shared_ptr<Cert> CertPtr;
+
+class ParsedContentObject
+{
+public:
+ enum Type
+ {
+ DATA,
+ KEY,
+ OTHER
+ };
+ ParsedContentObject(const unsigned char *data, size_t len, bool verified = false);
+ ParsedContentObject(const unsigned char *data, const ccn_parsed_ContentObject &pco, bool verified = false);
+ ParsedContentObject(const Bytes &bytes, bool verified = false);
+ ParsedContentObject(const ParsedContentObject &other, bool verified = false);
+ virtual ~ParsedContentObject();
+
+ Bytes
+ content() const;
+
+ BytesPtr
+ contentPtr() const;
+
+ Name
+ name() const;
+
+ Name
+ keyName() const;
+
+ HashPtr
+ publisherPublicKeyDigest() const;
+
+ Type
+ type() const;
+
+ inline const Bytes &
+ buf () const;
+
+ bool
+ verified() const { return m_verified; }
+
+ // void
+ // verifySignature(const CertPtr &cert);
+
+ const unsigned char *
+ msg() const { return head(m_bytes); }
+
+ const ccn_parsed_ContentObject *
+ pco() const { return &m_pco; }
+
+private:
+ void
+ init(const unsigned char *data, size_t len);
+
+protected:
+ ccn_parsed_ContentObject m_pco;
+ ccn_indexbuf *m_comps;
+ Bytes m_bytes;
+ bool m_verified;
+ bool m_integrityChecked;
+};
+
+typedef boost::shared_ptr<ParsedContentObject> PcoPtr;
+
+namespace Error {
+struct MisformedContentObject : virtual boost::exception, virtual std::exception { };
+}
+
+const Bytes &
+ParsedContentObject::buf () const
+{
+ return m_bytes;
+}
+
+
+}
+
+#endif // NDN_CONTENT_OBJECT_H
diff --git a/disabled/verifier.cc b/disabled/verifier.cc
new file mode 100644
index 0000000..99599bd
--- /dev/null
+++ b/disabled/verifier.cc
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 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>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "verifier.h"
+#include "ndn.cxx/wrapper.h"
+#include "logging.h"
+
+INIT_LOGGER ("ndn.Verifier");
+namespace ndn {
+
+static const size_t ROOT_KEY_DIGEST_LEN = 32; // SHA-256
+static const unsigned char ROOT_KEY_DIGEST[ROOT_KEY_DIGEST_LEN] = {0xa7, 0xd9, 0x8b, 0x81, 0xde, 0x13, 0xfc,
+0x56, 0xc5, 0xa6, 0x92, 0xb4, 0x44, 0x93, 0x6e, 0x56, 0x70, 0x9d, 0x52, 0x6f, 0x70,
+0xed, 0x39, 0xef, 0xb5, 0xe2, 0x3, 0x29, 0xa5, 0x53, 0x3e, 0x68};
+
+Verifier::Verifier(Wrapper *ccnx)
+ : m_ccnx(ccnx)
+ , m_rootKeyDigest(ROOT_KEY_DIGEST, ROOT_KEY_DIGEST_LEN)
+{
+}
+
+Verifier::~Verifier()
+{
+}
+
+bool
+Verifier::verify(PcoPtr pco, double maxWait)
+{
+ _LOG_TRACE("Verifying content [" << pco->name() << "]");
+ HashPtr publisherPublicKeyDigest = pco->publisherPublicKeyDigest();
+
+ {
+ UniqueRecLock lock(m_cacheLock);
+ CertCache::iterator it = m_certCache.find(*publisherPublicKeyDigest);
+ if (it != m_certCache.end())
+ {
+ CertPtr cert = it->second;
+ if (cert->validity() == Cert::WITHIN_VALID_TIME_SPAN)
+ {
+ pco->verifySignature(cert);
+ return pco->verified();
+ }
+ else
+ {
+ // delete the invalid cert cache
+ m_certCache.erase(it);
+ }
+ }
+ }
+
+ // keyName is the name specified in key locator, i.e. without version and segment
+ Name keyName = pco->keyName();
+ int keyNameSize = keyName.size();
+
+ if (keyNameSize < 2)
+ {
+ _LOG_ERROR("Key name is empty or has too few components.");
+ return false;
+ }
+
+ // for keys, we have to make sure key name is strictly prefix of the content name
+ if (pco->type() == ParsedContentObject::KEY)
+ {
+ Name contentName = pco->name();
+ // when checking for prefix, do not include the hash in the key name (which is the last component)
+ Name keyNamePrefix = keyName.getPrefix (keyNameSize - 1);
+ if (keyNamePrefix.size() >= contentName.size() || contentName.getPrefix (keyNamePrefix.size()) != keyNamePrefix)
+ {
+ _LOG_ERROR("Key name prefix [" << keyNamePrefix << "] is not the prefix of content name [" << contentName << "]");
+ return false;
+ }
+ }
+ else
+ {
+ // for now, user can assign any data using his key
+ }
+
+ Name metaName;
+ metaName
+ .append (keyName.getPrefix (keyNameSize - 1))
+ .append ("info")
+ .append (keyName.getSubName (keyNameSize - 1));
+
+ Interest interest;
+ interest.setChildSelector (Interest::CHILD_RIGHT)
+ .setInterestLifetime(maxWait);
+
+ PcoPtr keyObject = m_ccnx->get(Interest (interest).setName (keyName), maxWait);
+ PcoPtr metaObject = m_ccnx->get(Interest (interest).setName (metaName), maxWait);
+ if (!keyObject || !metaObject )
+ {
+ _LOG_ERROR("can not fetch key or meta");
+ return false;
+ }
+
+ HashPtr publisherKeyHashInKeyObject = keyObject->publisherPublicKeyDigest();
+ HashPtr publisherKeyHashInMetaObject = metaObject->publisherPublicKeyDigest();
+
+ // make sure key and meta are signed using the same key
+ if (publisherKeyHashInKeyObject->IsZero() || ! (*publisherKeyHashInKeyObject == *publisherKeyHashInMetaObject))
+ {
+ _LOG_ERROR("Key and Meta not signed by the same publisher");
+ return false;
+ }
+
+ CertPtr cert = boost::make_shared<Cert>(keyObject, metaObject);
+ if (cert->validity() != Cert::WITHIN_VALID_TIME_SPAN)
+ {
+ _LOG_ERROR("Certificate is not valid, validity status is : " << cert->validity());
+ return false;
+ }
+
+ // check pco is actually signed by this key (i.e. we don't trust the publisherPublicKeyDigest given by ccnx c lib)
+ if (! (*pco->publisherPublicKeyDigest() == cert->keyDigest()))
+ {
+ _LOG_ERROR("key digest does not match the publisher public key digest of the content object");
+ return false;
+ }
+
+ // now we only need to make sure the key is trustworthy
+ if (cert->keyDigest() == m_rootKeyDigest)
+ {
+ // the key is the root key
+ // do nothing now
+ }
+ else
+ {
+ // can not verify key or can not verify meta
+ if (!verify(keyObject, maxWait) || !verify(metaObject, maxWait))
+ {
+ _LOG_ERROR("Can not verify key or meta");
+ return false;
+ }
+ }
+
+ // ok, keyObject verified, because metaObject is signed by the same parent key and integrity checked
+ // so metaObject is also verified
+ {
+ UniqueRecLock lock(m_cacheLock);
+ m_certCache.insert(std::make_pair(cert->keyDigest(), cert));
+ }
+
+ pco->verifySignature(cert);
+ if (pco->verified())
+ {
+ _LOG_TRACE("[" << pco->name() << "] VERIFIED.");
+ }
+ else
+ {
+ _LOG_ERROR("[" << pco->name() << "] CANNOT BE VERIFIED.");
+ }
+ return pco->verified();
+}
+
+} // ndn
diff --git a/disabled/verifier.h b/disabled/verifier.h
new file mode 100644
index 0000000..0065d87
--- /dev/null
+++ b/disabled/verifier.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 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>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_VERIFIER_H
+#define NDN_VERIFIER_H
+
+#include "ndn.cxx/common.h"
+#include "ndn.cxx/name.h"
+#include "ndn.cxx/cert.h"
+#include "ndn.cxx/pco.h"
+#include <map>
+#include <boost/thread/locks.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <boost/thread/thread.hpp>
+
+namespace ndn {
+
+class Wrapper;
+
+class Verifier
+{
+public:
+ Verifier(Wrapper *ccnx);
+ ~Verifier();
+
+ bool verify(PcoPtr pco, double maxWait);
+
+private:
+
+private:
+ Wrapper *m_ccnx;
+ Hash m_rootKeyDigest;
+ typedef std::map<Hash, CertPtr> CertCache;
+ CertCache m_certCache;
+ typedef boost::recursive_mutex RecLock;
+ typedef boost::unique_lock<RecLock> UniqueRecLock;
+ RecLock m_cacheLock;
+};
+
+} // ndn
+
+#endif // NDN_VERIFIER_H
diff --git a/disabled/wrapper-tests.cc b/disabled/wrapper-tests.cc
new file mode 100644
index 0000000..c69ca54
--- /dev/null
+++ b/disabled/wrapper-tests.cc
@@ -0,0 +1,248 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+
+#include "ndn.cxx.h"
+#include <unistd.h>
+#include <fstream>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/make_shared.hpp>
+
+#include "logging.h"
+
+using namespace ndn;
+using namespace std;
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE(WrapperTests)
+
+WrapperPtr c1;
+WrapperPtr c2;
+int g_timeout_counter = 0;
+int g_dataCallback_counter = 0;
+
+void publish1(InterestPtr interest)
+{
+ string content = interest->getName ().toUri();
+ c1->publishData(interest->getName (), (const unsigned char*)content.c_str(), content.size(), 5);
+}
+
+void publish2(InterestPtr interest)
+{
+ string content = interest->getName ().toUri();
+ c2->publishData(interest->getName (), (const unsigned char*)content.c_str(), content.size(), 5);
+}
+
+void dataCallback(const Name &name, ndn::PcoPtr pco)
+{
+ cout << " in data callback" << endl;
+ BytesPtr content = pco->contentPtr ();
+ string msg(reinterpret_cast<const char *> (head (*content)), content->size());
+ g_dataCallback_counter ++;
+ BOOST_CHECK_EQUAL(name, msg);
+}
+
+void encapCallback(const Name &name, ndn::PcoPtr pco)
+{
+ cout << " in encap data callback" << endl;
+ BOOST_CHECK(!c1->verify(pco));
+ cout << "++++++++++++++++++ Outer content couldn't be verified, which is expected." << endl;
+ PcoPtr npco = make_shared<ParsedContentObject> (*(pco->contentPtr()));
+ g_dataCallback_counter ++;
+ BOOST_CHECK(npco);
+ BOOST_CHECK(c1->verify(npco));
+}
+
+void
+timeout(const Name &name, const Closure &closure, InterestPtr origInterest)
+{
+ g_timeout_counter ++;
+}
+
+void
+setup()
+{
+ if (!c1)
+ {
+ c1 = make_shared<Wrapper> ();
+ }
+ if (!c2)
+ {
+ c2 = make_shared<Wrapper> ();
+ }
+}
+
+void
+teardown()
+{
+ if (c1)
+ {
+ c1.reset();
+ }
+ if (c2)
+ {
+ c2.reset();
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE (Basic)
+{
+ INIT_LOGGERS ();
+
+ setup();
+ Name prefix1("/c1");
+ Name prefix2("/c2");
+
+ c1->setInterestFilter(prefix1, bind(publish1, _1));
+ usleep(100000);
+ c2->setInterestFilter(prefix2, bind(publish2, _1));
+
+ Closure closure (bind(dataCallback, _1, _2), bind(timeout, _1, _2, _3));
+
+ c1->sendInterest(Name("/c2/hi"), closure);
+ usleep(100000);
+ c2->sendInterest(Name("/c1/hi"), closure);
+ sleep(1);
+ BOOST_CHECK_EQUAL(g_dataCallback_counter, 2);
+
+ // reset
+ g_dataCallback_counter = 0;
+ g_timeout_counter = 0;
+
+ teardown();
+}
+
+BOOST_AUTO_TEST_CASE (Selector)
+{
+ setup();
+ Closure closure (bind(dataCallback, _1, _2), bind(timeout, _1, _2, _3));
+
+ Interest interest;
+ interest
+ .setInterestLifetime(1)
+ .setChildSelector (Interest::CHILD_RIGHT);
+
+ string n1 = "/random/01";
+ c1->sendInterest (Interest (interest).setName (Name(n1)), closure);
+ sleep(2);
+ c2->publishData(Name(n1), (const unsigned char *)n1.c_str(), n1.size(), 1);
+ usleep(100000);
+ BOOST_CHECK_EQUAL(g_timeout_counter, 1);
+ BOOST_CHECK_EQUAL(g_dataCallback_counter, 0);
+
+ string n2 = "/random/02";
+ interest.setInterestLifetime(2);
+ c1->sendInterest(Interest (interest).setName (Name(n2)), closure);
+ sleep(1);
+ c2->publishData(Name(n2), (const unsigned char *)n2.c_str(), n2.size(), 1);
+ usleep(100000);
+ BOOST_CHECK_EQUAL(g_timeout_counter, 1);
+ BOOST_CHECK_EQUAL(g_dataCallback_counter, 1);
+
+ // reset
+ g_dataCallback_counter = 0;
+ g_timeout_counter = 0;
+
+ teardown();
+
+}
+
+void
+reexpress(const Name &name, const Closure &closure, InterestPtr origInterest)
+{
+ g_timeout_counter ++;
+ c1->sendInterest (*origInterest, closure);
+}
+
+BOOST_AUTO_TEST_CASE (Timeout)
+{
+ setup();
+ g_dataCallback_counter = 0;
+ g_timeout_counter = 0;
+ Closure closure (bind(dataCallback, _1, _2), bind(reexpress, _1, _2, _3));
+
+ string n1 = "/random/04";
+
+ Interest interest;
+ interest
+ .setInterestLifetime(1)
+ .setName (n1);
+
+ c1->sendInterest(interest, closure);
+ usleep(3500000);
+ c2->publishData(Name(n1), (const unsigned char *)n1.c_str(), n1.size(), 1);
+ usleep(100000);
+ BOOST_CHECK_EQUAL(g_dataCallback_counter, 1);
+ BOOST_CHECK_EQUAL(g_timeout_counter, 3);
+ teardown();
+}
+
+BOOST_AUTO_TEST_CASE (Unsigned)
+{
+ setup();
+ string n1 = "/xxxxxx/unsigned/001";
+ Closure closure (bind(dataCallback, _1, _2), bind(timeout, _1, _2, _3));
+
+ g_dataCallback_counter = 0;
+ c1->sendInterest(Name(n1), closure);
+ usleep(100000);
+ c2->publishUnsignedData(Name(n1), (const unsigned char *)n1.c_str(), n1.size(), 1);
+ usleep(100000);
+ BOOST_CHECK_EQUAL(g_dataCallback_counter, 1);
+
+ string n2 = "/xxxxxx/signed/001";
+ Bytes content = c1->createContentObject(Name(n1), (const unsigned char *)n2.c_str(), n2.size(), 1);
+
+ c1->publishUnsignedData(Name(n2), head(content), content.size(), 1);
+ Closure encapClosure(bind(encapCallback, _1, _2), bind(timeout, _1, _2, _3));
+ c2->sendInterest(Name(n2), encapClosure);
+ usleep(4000000);
+ BOOST_CHECK_EQUAL(g_dataCallback_counter, 2);
+ teardown();
+}
+
+
+ /*
+ BOOST_AUTO_TEST_CASE (ndnWrapperUnsigningTest)
+ {
+ setup();
+ Bytes data;
+ data.resize(1024);
+ for (int i = 0; i < 1024; i++)
+ {
+ data[i] = 'm';
+ }
+
+ Name name("/unsigningtest");
+
+ posix_time::ptime start = posix_time::second_clock::local_time();
+ for (uint64_t i = 0; i < 100000; i++)
+ {
+ Name n = name;
+ n.appendComp(i);
+ c1->publishUnsignedData(n, data, 10);
+ }
+ posix_time::ptime end = posix_time::second_clock::local_time();
+
+ posix_time::time_duration duration = end - start;
+
+ cout << "Publishing 100000 1K size content objects costs " <<duration.total_milliseconds() << " milliseconds" << endl;
+ cout << "Average time to publish one content object is " << (double) duration.total_milliseconds() / 100000.0 << " milliseconds" << endl;
+ teardown();
+ }
+ */
+
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/disabled/wrapper.cc b/disabled/wrapper.cc
new file mode 100644
index 0000000..4ef079e
--- /dev/null
+++ b/disabled/wrapper.cc
@@ -0,0 +1,791 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "wrapper.h"
+
+extern "C" {
+#include <ccn/fetch.h>
+}
+#include <poll.h>
+#include <boost/throw_exception.hpp>
+#include <boost/random.hpp>
+#include <boost/make_shared.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include <sstream>
+
+// #include "ndn.cxx/verifier.h"
+#include "executor/executor.h"
+
+#include "logging.h"
+#include "ndn.cxx/wire/ccnb.h"
+
+
+INIT_LOGGER ("ndn.Wrapper");
+
+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;
+
+namespace ndn {
+
+// hack to enable fake signatures
+// min length for signature field is 16, as defined in ccn_buf_decoder.c:728
+const int DEFAULT_SIGNATURE_SIZE = 16;
+
+// Although ccn_buf_decoder.c:745 defines minimum length 16, something else is checking and only 32-byte fake value is accepted by ccnd
+const int PUBLISHER_KEY_SIZE = 32;
+
+static int
+ccn_encode_garbage_Signature(struct ccn_charbuf *buf)
+{
+ int res = 0;
+
+ res |= ccn_charbuf_append_tt(buf, CCN_DTAG_Signature, CCN_DTAG);
+
+ // Let's cheat more. Default signing algorithm in ccnd is SHA256, so we just need add 32 bytes of garbage
+ static char garbage [DEFAULT_SIGNATURE_SIZE];
+
+ // digest and witness fields are optional, so use default ones
+
+ res |= ccn_charbuf_append_tt(buf, CCN_DTAG_SignatureBits, CCN_DTAG);
+ res |= ccn_charbuf_append_tt(buf, DEFAULT_SIGNATURE_SIZE, CCN_BLOB);
+ res |= ccn_charbuf_append(buf, garbage, DEFAULT_SIGNATURE_SIZE);
+ res |= ccn_charbuf_append_closer(buf);
+
+ res |= ccn_charbuf_append_closer(buf);
+
+ return(res == 0 ? 0 : -1);
+}
+
+static int
+ccn_pack_unsigned_ContentObject(struct ccn_charbuf *buf,
+ const struct ccn_charbuf *Name,
+ const struct ccn_charbuf *SignedInfo,
+ const void *data,
+ size_t size)
+{
+ int res = 0;
+ struct ccn_charbuf *content_header;
+ size_t closer_start;
+
+ content_header = ccn_charbuf_create();
+ res |= ccn_charbuf_append_tt(content_header, CCN_DTAG_Content, CCN_DTAG);
+ if (size != 0)
+ res |= ccn_charbuf_append_tt(content_header, size, CCN_BLOB);
+ closer_start = content_header->length;
+ res |= ccn_charbuf_append_closer(content_header);
+ if (res < 0)
+ return(-1);
+
+ res |= ccn_charbuf_append_tt(buf, CCN_DTAG_ContentObject, CCN_DTAG);
+
+ res |= ccn_encode_garbage_Signature(buf);
+
+ res |= ccn_charbuf_append_charbuf(buf, Name);
+ res |= ccn_charbuf_append_charbuf(buf, SignedInfo);
+ res |= ccnb_append_tagged_blob(buf, CCN_DTAG_Content, data, size);
+ res |= ccn_charbuf_append_closer(buf);
+
+ ccn_charbuf_destroy(&content_header);
+ return(res == 0 ? 0 : -1);
+}
+
+Wrapper::Wrapper()
+ : m_handle (0)
+ , m_running (true)
+ , m_connected (false)
+ , m_executor (new Executor(1))
+ // , m_verifier(new Verifier(this))
+{
+ start ();
+}
+
+void
+Wrapper::connectCcnd()
+{
+ if (m_handle != 0) {
+ ccn_disconnect (m_handle);
+ //ccn_destroy (&m_handle);
+ }
+ else
+ {
+ m_handle = ccn_create ();
+ }
+
+ UniqueRecLock lock(m_mutex);
+ if (ccn_connect(m_handle, NULL) < 0)
+ {
+ BOOST_THROW_EXCEPTION (Error::ndnOperation() << errmsg_info_str("connection to ccnd failed"));
+ }
+ m_connected = true;
+
+ if (!m_registeredInterests.empty())
+ {
+ for (map<Name, InterestCallback>::const_iterator it = m_registeredInterests.begin(); it != m_registeredInterests.end(); ++it)
+ {
+ clearInterestFilter(it->first, false);
+ setInterestFilter(it->first, it->second, false);
+ }
+ }
+}
+
+Wrapper::~Wrapper()
+{
+ shutdown ();
+ // if (m_verifier != 0)
+ // {
+ // delete m_verifier;
+ // m_verifier = 0;
+ // }
+}
+
+void
+Wrapper::start () // called automatically in constructor
+{
+ connectCcnd();
+ m_thread = thread (&Wrapper::ccnLoop, this);
+ m_executor->start();
+}
+
+void
+Wrapper::shutdown () // called in destructor, but can called manually
+{
+ m_executor->shutdown();
+
+ {
+ UniqueRecLock lock(m_mutex);
+ m_running = false;
+ }
+
+ _LOG_DEBUG ("+++++++++SHUTDOWN+++++++");
+ if (m_connected)
+ {
+ m_thread.join ();
+
+ ccn_disconnect (m_handle);
+ //ccn_destroy (&m_handle);
+ m_connected = false;
+ }
+}
+
+void
+Wrapper::ccnLoop ()
+{
+ static boost::mt19937 randomGenerator (static_cast<unsigned int> (std::time (0)));
+ static boost::variate_generator<boost::mt19937&, boost::uniform_int<> > rangeUniformRandom (randomGenerator, uniform_int<> (0,1000));
+
+ while (m_running)
+ {
+ try
+ {
+ int res = 0;
+ {
+ UniqueRecLock lock(m_mutex);
+ res = ccn_run (m_handle, 0);
+ }
+
+ if (!m_running) break;
+
+ if (res < 0) {
+ _LOG_ERROR ("ccn_run returned negative status: " << res);
+
+ BOOST_THROW_EXCEPTION (Error::ndnOperation()
+ << errmsg_info_str("ccn_run returned error"));
+ }
+
+
+ pollfd pfds[1];
+ {
+ UniqueRecLock lock(m_mutex);
+
+ pfds[0].fd = ccn_get_connection_fd (m_handle);
+ pfds[0].events = POLLIN;
+ if (ccn_output_is_pending (m_handle))
+ pfds[0].events |= POLLOUT;
+ }
+
+ int ret = poll (pfds, 1, 1);
+ if (ret < 0)
+ {
+ BOOST_THROW_EXCEPTION (Error::ndnOperation() << errmsg_info_str("ccnd socket failed (probably ccnd got stopped)"));
+ }
+ }
+ catch (Error::ndnOperation &e)
+ {
+ m_connected = false;
+ // probably ccnd has been stopped
+ // try reconnect with sleep
+ int interval = 1;
+ int maxInterval = 32;
+ while (m_running)
+ {
+ try
+ {
+ this_thread::sleep (boost::get_system_time () + time::Seconds (interval) + time::Milliseconds (rangeUniformRandom ()));
+
+ connectCcnd ();
+ _LOG_DEBUG("reconnect to ccnd succeeded");
+ break;
+ }
+ catch (Error::ndnOperation &e)
+ {
+ this_thread::sleep (boost::get_system_time () + time::Seconds (interval) + time::Milliseconds (rangeUniformRandom ()));
+
+ // do exponential backup for reconnect interval
+ if (interval < maxInterval)
+ {
+ interval *= 2;
+ }
+ }
+ }
+ }
+ catch (const std::exception &exc)
+ {
+ // catch anything thrown within try block that derives from std::exception
+ std::cerr << exc.what();
+ }
+ catch (...)
+ {
+ cout << "UNKNOWN EXCEPTION !!!" << endl;
+ }
+ }
+}
+
+Bytes
+Wrapper::createContentObject(const Name &name, const void *buf, size_t len, int freshness, const Name &keyNameParam)
+{
+ {
+ UniqueRecLock lock(m_mutex);
+ if (!m_running || !m_connected)
+ {
+ _LOG_TRACE ("<< not running or connected");
+ return Bytes ();
+ }
+ }
+
+ ccn_charbuf *content = ccn_charbuf_create();
+
+ struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
+ sp.freshness = freshness;
+
+ Name keyName;
+
+ if (keyNameParam.size() == 0)
+ {
+ // use default key name
+ CharbufPtr defaultKeyNamePtr = boost::make_shared<Charbuf>();
+ ccn_get_public_key_and_name(m_handle, &sp, NULL, NULL, defaultKeyNamePtr->getBuf());
+ keyName = Name(*defaultKeyNamePtr);
+
+ _LOG_DEBUG ("DEFAULT KEY NAME: " << keyName);
+ }
+ else
+ {
+ keyName = keyNameParam;
+ }
+
+ if (sp.template_ccnb == NULL)
+ {
+ sp.template_ccnb = ccn_charbuf_create();
+ ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_SignedInfo, CCN_DTAG);
+ }
+ // no idea what the following 3 lines do, but it was there
+ else if (sp.template_ccnb->length > 0) {
+ sp.template_ccnb->length--;
+ }
+ ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_KeyLocator, CCN_DTAG);
+ ccn_charbuf_append_tt(sp.template_ccnb, CCN_DTAG_KeyName, CCN_DTAG);
+
+ charbuf_stream keyStream;
+ wire::Ccnb::appendName (keyStream, keyName);
+
+ ccn_charbuf_append(sp.template_ccnb, keyStream.buf ().getBuf ()->buf, keyStream.buf ().getBuf ()->length);
+ ccn_charbuf_append_closer(sp.template_ccnb); // </KeyName>
+ ccn_charbuf_append_closer(sp.template_ccnb); // </KeyLocator>
+ sp.sp_flags |= CCN_SP_TEMPL_KEY_LOCATOR;
+ ccn_charbuf_append_closer(sp.template_ccnb); // </SignedInfo>
+
+ charbuf_stream nameStream;
+ wire::Ccnb::appendName (nameStream, name);
+
+ if (ccn_sign_content(m_handle, content, nameStream.buf ().getBuf (), &sp, buf, len) != 0)
+ {
+ BOOST_THROW_EXCEPTION(Error::ndnOperation() << errmsg_info_str("sign content failed"));
+ }
+
+ Bytes bytes;
+ readRaw(bytes, content->buf, content->length);
+
+ ccn_charbuf_destroy (&content);
+ if (sp.template_ccnb != NULL)
+ {
+ ccn_charbuf_destroy (&sp.template_ccnb);
+ }
+
+ return bytes;
+}
+
+int
+Wrapper::putToCcnd (const Bytes &contentObject)
+{
+ _LOG_TRACE (">> putToCcnd");
+ UniqueRecLock lock(m_mutex);
+ if (!m_running || !m_connected)
+ {
+ _LOG_TRACE ("<< not running or connected");
+ return -1;
+ }
+
+
+ if (ccn_put(m_handle, head(contentObject), contentObject.size()) < 0)
+ {
+ _LOG_ERROR ("ccn_put failed");
+ // BOOST_THROW_EXCEPTION(Error::ndnOperation() << errmsg_info_str("ccnput failed"));
+ }
+ else
+ {
+ _LOG_DEBUG ("<< putToCcnd");
+ }
+
+ return 0;
+}
+
+int
+Wrapper::publishData (const Name &name, const unsigned char *buf, size_t len, int freshness, const Name &keyName)
+{
+ _LOG_TRACE ("publishData: " << name);
+ Bytes co = createContentObject(name, buf, len, freshness, keyName);
+ return putToCcnd(co);
+}
+
+int
+Wrapper::publishUnsignedData(const Name &name, const unsigned char *buf, size_t len, int freshness)
+{
+ _LOG_TRACE ("publishUnsignedData: " << name);
+ {
+ UniqueRecLock lock(m_mutex);
+ if (!m_running || !m_connected)
+ {
+ _LOG_TRACE ("<< not running or connected");
+ return -1;
+ }
+ }
+
+ ccn_charbuf *content = ccn_charbuf_create();
+ ccn_charbuf *signed_info = ccn_charbuf_create();
+
+ static char fakeKey[PUBLISHER_KEY_SIZE];
+
+ int res = ccn_signed_info_create(signed_info,
+ fakeKey, PUBLISHER_KEY_SIZE,
+ NULL,
+ CCN_CONTENT_DATA,
+ freshness,
+ NULL,
+ NULL // ccnd is happy with absent key locator and key itself... ha ha
+ );
+
+ charbuf_stream nameStream;
+ wire::Ccnb::appendName (nameStream, name);
+
+ ccn_pack_unsigned_ContentObject(content, nameStream.buf ().getBuf (), signed_info, buf, len);
+
+ Bytes bytes;
+ readRaw(bytes, content->buf, content->length);
+
+ ccn_charbuf_destroy (&content);
+ ccn_charbuf_destroy (&signed_info);
+
+ return putToCcnd (bytes);
+}
+
+
+static void
+deleterInInterestTuple (tuple<Wrapper::InterestCallback *, ExecutorPtr> *tuple)
+{
+ delete tuple->get<0> ();
+ delete tuple;
+}
+
+static ccn_upcall_res
+incomingInterest(ccn_closure *selfp,
+ ccn_upcall_kind kind,
+ ccn_upcall_info *info)
+{
+ Wrapper::InterestCallback *f;
+ ExecutorPtr executor;
+ tuple<Wrapper::InterestCallback *, ExecutorPtr> *realData = reinterpret_cast< tuple<Wrapper::InterestCallback *, ExecutorPtr>* > (selfp->data);
+ tie (f, executor) = *realData;
+
+ switch (kind)
+ {
+ case CCN_UPCALL_FINAL: // effective in unit tests
+ // delete closure;
+ executor->execute (bind (deleterInInterestTuple, realData));
+
+ delete selfp;
+ _LOG_TRACE ("<< incomingInterest with CCN_UPCALL_FINAL");
+ return CCN_UPCALL_RESULT_OK;
+
+ case CCN_UPCALL_INTEREST:
+ _LOG_TRACE (">> incomingInterest upcall: " << Name(info->interest_ccnb, info->interest_comps));
+ break;
+
+ default:
+ _LOG_TRACE ("<< incomingInterest with CCN_UPCALL_RESULT_OK: " << Name(info->interest_ccnb, info->interest_comps));
+ return CCN_UPCALL_RESULT_OK;
+ }
+
+ InterestPtr interest = make_shared<Interest> (info->pi);
+ interest->setName (Name (info->interest_ccnb, info->interest_comps));
+
+ executor->execute (bind (*f, interest));
+ // this will be run in executor
+ // (*f) (interest);
+ // closure->runInterestCallback(interest);
+
+ return CCN_UPCALL_RESULT_OK;
+}
+
+static void
+deleterInDataTuple (tuple<Closure *, ExecutorPtr, InterestPtr> *tuple)
+{
+ delete tuple->get<0> ();
+ delete tuple;
+}
+
+static ccn_upcall_res
+incomingData(ccn_closure *selfp,
+ ccn_upcall_kind kind,
+ ccn_upcall_info *info)
+{
+ // Closure *cp = static_cast<Closure *> (selfp->data);
+ Closure *cp;
+ ExecutorPtr executor;
+ InterestPtr interest;
+ tuple<Closure *, ExecutorPtr, InterestPtr> *realData = reinterpret_cast< tuple<Closure*, ExecutorPtr, InterestPtr>* > (selfp->data);
+ tie (cp, executor, interest) = *realData;
+
+ switch (kind)
+ {
+ case CCN_UPCALL_FINAL: // effecitve in unit tests
+ executor->execute (bind (deleterInDataTuple, realData));
+
+ cp = NULL;
+ delete selfp;
+ _LOG_TRACE ("<< incomingData with CCN_UPCALL_FINAL");
+ return CCN_UPCALL_RESULT_OK;
+
+ case CCN_UPCALL_CONTENT:
+ _LOG_TRACE (">> incomingData content upcall: " << Name (info->content_ccnb, info->content_comps));
+ break;
+
+ // this is the case where the intentionally unsigned packets coming (in Encapsulation case)
+ case CCN_UPCALL_CONTENT_BAD:
+ _LOG_TRACE (">> incomingData content bad upcall: " << Name (info->content_ccnb, info->content_comps));
+ break;
+
+ // always ask ccnd to try to fetch the key
+ case CCN_UPCALL_CONTENT_UNVERIFIED:
+ _LOG_TRACE (">> incomingData content unverified upcall: " << Name (info->content_ccnb, info->content_comps));
+ break;
+
+ case CCN_UPCALL_INTEREST_TIMED_OUT: {
+ if (cp != NULL)
+ {
+ Name interestName (info->interest_ccnb, info->interest_comps);
+ _LOG_TRACE ("<< incomingData timeout: " << Name (info->interest_ccnb, info->interest_comps));
+ executor->execute (bind (&Closure::runTimeoutCallback, cp, interestName, *cp, interest));
+ }
+ else
+ {
+ _LOG_TRACE ("<< incomingData timeout, but callback is not set...: " << Name (info->interest_ccnb, info->interest_comps));
+ }
+ return CCN_UPCALL_RESULT_OK;
+ }
+
+ default:
+ _LOG_TRACE(">> unknown upcall type");
+ return CCN_UPCALL_RESULT_OK;
+ }
+
+ PcoPtr pco = make_shared<ParsedContentObject> (info->content_ccnb, info->pco->offset[CCN_PCO_E]);
+
+ // this will be run in executor
+ executor->execute (bind (&Closure::runDataCallback, cp, pco->name (), pco));
+ _LOG_TRACE (">> incomingData");
+
+ return CCN_UPCALL_RESULT_OK;
+}
+
+int Wrapper::sendInterest (const Interest &interest, const Closure &closure)
+{
+ _LOG_TRACE (">> sendInterest: " << interest.getName ());
+ {
+ UniqueRecLock lock(m_mutex);
+ if (!m_running || !m_connected)
+ {
+ _LOG_ERROR ("<< sendInterest: not running or connected");
+ return -1;
+ }
+ }
+
+ ccn_closure *dataClosure = new ccn_closure;
+
+ // Closure *myClosure = new ExecutorClosure(closure, m_executor);
+ Closure *myClosure = closure.dup ();
+ dataClosure->data = new tuple<Closure*, ExecutorPtr, InterestPtr> (myClosure, m_executor, make_shared<Interest> (interest));
+
+ dataClosure->p = &incomingData;
+
+ UniqueRecLock lock(m_mutex);
+
+ charbuf_stream nameStream;
+ wire::Ccnb::appendName (nameStream, interest.getName ());
+
+ charbuf_stream interestStream;
+ wire::Ccnb::appendInterest (interestStream, interest);
+
+ if (ccn_express_interest (m_handle, nameStream.buf ().getBuf (),
+ dataClosure,
+ interestStream.buf ().getBuf ()
+ ) < 0)
+ {
+ _LOG_ERROR ("<< sendInterest: ccn_express_interest FAILED!!!");
+ }
+
+ return 0;
+}
+
+int Wrapper::setInterestFilter (const Name &prefix, const InterestCallback &interestCallback, bool record/* = true*/)
+{
+ _LOG_TRACE (">> setInterestFilter");
+ UniqueRecLock lock(m_mutex);
+ if (!m_running || !m_connected)
+ {
+ return -1;
+ }
+
+ ccn_closure *interestClosure = new ccn_closure;
+
+ // interestClosure->data = new ExecutorInterestClosure(interestCallback, m_executor);
+
+ interestClosure->data = new tuple<Wrapper::InterestCallback *, ExecutorPtr> (new InterestCallback (interestCallback), m_executor); // should be removed when closure is removed
+ interestClosure->p = &incomingInterest;
+
+ charbuf_stream prefixStream;
+ wire::Ccnb::appendName (prefixStream, prefix);
+
+ int ret = ccn_set_interest_filter (m_handle, prefixStream.buf ().getBuf (), interestClosure);
+ if (ret < 0)
+ {
+ _LOG_ERROR ("<< setInterestFilter: ccn_set_interest_filter FAILED");
+ }
+
+ if (record)
+ {
+ m_registeredInterests.insert(pair<Name, InterestCallback>(prefix, interestCallback));
+ }
+
+ _LOG_TRACE ("<< setInterestFilter");
+
+ return ret;
+}
+
+void
+Wrapper::clearInterestFilter (const Name &prefix, bool record/* = true*/)
+{
+ _LOG_TRACE (">> clearInterestFilter");
+ UniqueRecLock lock(m_mutex);
+ if (!m_running || !m_connected)
+ return;
+
+ charbuf_stream prefixStream;
+ wire::Ccnb::appendName (prefixStream, prefix);
+
+ int ret = ccn_set_interest_filter (m_handle, prefixStream.buf ().getBuf (), 0);
+ if (ret < 0)
+ {
+ }
+
+ if (record)
+ {
+ m_registeredInterests.erase(prefix);
+ }
+
+ _LOG_TRACE ("<< clearInterestFilter");
+}
+
+Name
+Wrapper::getLocalPrefix ()
+{
+ struct ccn * tmp_handle = ccn_create ();
+ int res = ccn_connect (tmp_handle, NULL);
+ if (res < 0)
+ {
+ return Name();
+ }
+
+ string retval = "";
+
+ struct ccn_charbuf *templ = ccn_charbuf_create();
+ ccn_charbuf_append_tt(templ, CCN_DTAG_Interest, CCN_DTAG);
+ ccn_charbuf_append_tt(templ, CCN_DTAG_Name, CCN_DTAG);
+ ccn_charbuf_append_closer(templ); /* </Name> */
+ // XXX - use pubid if possible
+ ccn_charbuf_append_tt(templ, CCN_DTAG_MaxSuffixComponents, CCN_DTAG);
+ ccnb_append_number(templ, 1);
+ ccn_charbuf_append_closer(templ); /* </MaxSuffixComponents> */
+ ccnb_tagged_putf(templ, CCN_DTAG_Scope, "%d", 2);
+ ccn_charbuf_append_closer(templ); /* </Interest> */
+
+ struct ccn_charbuf *name = ccn_charbuf_create ();
+ res = ccn_name_from_uri (name, "/local/ndn/prefix");
+ if (res < 0) {
+ }
+ else
+ {
+ struct ccn_fetch *fetch = ccn_fetch_new (tmp_handle);
+
+ struct ccn_fetch_stream *stream = ccn_fetch_open (fetch, name, "/local/ndn/prefix",
+ NULL, 4, CCN_V_HIGHEST, 0);
+ if (stream == NULL) {
+ }
+ else
+ {
+ ostringstream os;
+
+ int counter = 0;
+ char buf[256];
+ while (true) {
+ res = ccn_fetch_read (stream, buf, sizeof(buf));
+
+ if (res == 0) {
+ break;
+ }
+
+ if (res > 0) {
+ os << string(buf, res);
+ } else if (res == CCN_FETCH_READ_NONE) {
+ if (counter < 2)
+ {
+ ccn_run(tmp_handle, 1000);
+ counter ++;
+ }
+ else
+ {
+ break;
+ }
+ } else if (res == CCN_FETCH_READ_END) {
+ break;
+ } else if (res == CCN_FETCH_READ_TIMEOUT) {
+ break;
+ } else {
+ break;
+ }
+ }
+ retval = os.str ();
+ stream = ccn_fetch_close(stream);
+ }
+ fetch = ccn_fetch_destroy(fetch);
+ }
+
+ ccn_charbuf_destroy (&name);
+
+ ccn_disconnect (tmp_handle);
+ ccn_destroy (&tmp_handle);
+
+ boost::algorithm::trim(retval);
+ return Name(retval);
+}
+
+bool
+Wrapper::verify(PcoPtr &pco, double maxWait)
+{
+ return true; // totally fake
+ // return m_verifier->verify(pco, maxWait);
+}
+
+/// @cond include_hidden
+// This is needed just for get function implementation
+struct GetState
+{
+ GetState (double maxWait)
+ {
+ double intPart, fraction;
+ fraction = modf (std::abs(maxWait), &intPart);
+
+ m_maxWait = time::Now ()
+ + time::Seconds (intPart)
+ + time::Microseconds (fraction * 1000000);
+ }
+
+ PcoPtr
+ WaitForResult ()
+ {
+ //_LOG_TRACE("GetState::WaitForResult start");
+ boost::unique_lock<boost::mutex> lock (m_mutex);
+ m_cond.timed_wait (lock, m_maxWait);
+ //_LOG_TRACE("GetState::WaitForResult finish");
+
+ return m_retval;
+ }
+
+ void
+ DataCallback (Name name, PcoPtr pco)
+ {
+ //_LOG_TRACE("GetState::DataCallback, Name [" << name << "]");
+ boost::unique_lock<boost::mutex> lock (m_mutex);
+ m_retval = pco;
+ m_cond.notify_one ();
+ }
+
+ void
+ TimeoutCallback (Name name)
+ {
+ boost::unique_lock<boost::mutex> lock (m_mutex);
+ m_cond.notify_one ();
+ }
+
+private:
+ Time m_maxWait;
+
+ boost::mutex m_mutex;
+ boost::condition_variable m_cond;
+
+ PcoPtr m_retval;
+};
+/// @endcond
+
+PcoPtr
+Wrapper::get(const Interest &interest, double maxWait/* = 4.0*/)
+{
+ _LOG_TRACE (">> get: " << interest.getName ());
+ {
+ UniqueRecLock lock(m_mutex);
+ if (!m_running || !m_connected)
+ {
+ _LOG_ERROR ("<< get: not running or connected");
+ return PcoPtr ();
+ }
+ }
+
+ GetState state (maxWait);
+ this->sendInterest (interest, Closure (boost::bind (&GetState::DataCallback, &state, _1, _2),
+ boost::bind (&GetState::TimeoutCallback, &state, _1)));
+ return state.WaitForResult ();
+}
+
+}
diff --git a/disabled/wrapper.h b/disabled/wrapper.h
new file mode 100644
index 0000000..517a832
--- /dev/null
+++ b/disabled/wrapper.h
@@ -0,0 +1,161 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_WRAPPER_H
+#define NDN_WRAPPER_H
+
+#include <boost/thread/locks.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <boost/thread/thread.hpp>
+
+#include "ndn.cxx/common.h"
+#include "ndn.cxx/fields/name.h"
+#include "ndn.cxx/interest.h"
+#include "ndn.cxx/closure.h"
+#include "ndn.cxx/pco.h"
+
+class Executor;
+typedef boost::shared_ptr<Executor> ExecutorPtr;
+
+namespace ndn {
+
+class Verifier;
+class Wrapper
+{
+public:
+ const static int MAX_FRESHNESS = 2147; // max value for ccnx
+ const static int DEFAULT_FRESHNESS = 60;
+ typedef boost::function<void (InterestPtr)> InterestCallback;
+
+ Wrapper();
+ ~Wrapper();
+
+ void
+ start (); // called automatically in constructor
+
+ /**
+ * @brief Because of uncertainty with executor, in some case it is necessary to call shutdown explicitly (see test-server-and-fetch.cc)
+ */
+ void
+ shutdown (); // called in destructor, but can called manually
+
+ int
+ setInterestFilter (const Name &prefix, const InterestCallback &interestCallback, bool record = true);
+
+ void
+ clearInterestFilter (const Name &prefix, bool record = true);
+
+ int
+ sendInterest (const Interest &interest, const Closure &closure);
+
+ int
+ publishData (const Name &name, const unsigned char *buf, size_t len, int freshness = DEFAULT_FRESHNESS, const Name &keyName=Name());
+
+ inline int
+ publishData (const Name &name, const Bytes &content, int freshness = DEFAULT_FRESHNESS, const Name &keyName=Name());
+
+ inline int
+ publishData (const Name &name, const std::string &content, int freshness = DEFAULT_FRESHNESS, const Name &keyName=Name());
+
+ int
+ publishUnsignedData(const Name &name, const unsigned char *buf, size_t len, int freshness = DEFAULT_FRESHNESS);
+
+ inline int
+ publishUnsignedData(const Name &name, const Bytes &content, int freshness = DEFAULT_FRESHNESS);
+
+ inline int
+ publishUnsignedData(const Name &name, const std::string &content, int freshness = DEFAULT_FRESHNESS);
+
+ static Name
+ getLocalPrefix ();
+
+ Bytes
+ createContentObject(const Name &name, const void *buf, size_t len, int freshness = DEFAULT_FRESHNESS, const Name &keyNameParam=Name());
+
+ int
+ putToCcnd (const Bytes &contentObject);
+
+ bool
+ verify(PcoPtr &pco, double maxWait = 1 /*seconds*/);
+
+ PcoPtr
+ get (const Interest &interest, double maxWait = 4.0/*seconds*/);
+
+private:
+ Wrapper(const Wrapper &other) {}
+
+protected:
+ void
+ connectCcnd();
+
+ /// @cond include_hidden
+ void
+ ccnLoop ();
+
+ /// @endcond
+
+protected:
+ typedef boost::shared_mutex Lock;
+ typedef boost::unique_lock<Lock> WriteLock;
+ typedef boost::shared_lock<Lock> ReadLock;
+
+ typedef boost::recursive_mutex RecLock;
+ typedef boost::unique_lock<RecLock> UniqueRecLock;
+
+ ccn* m_handle;
+ RecLock m_mutex;
+ boost::thread m_thread;
+ bool m_running;
+ bool m_connected;
+ std::map<Name, InterestCallback> m_registeredInterests;
+ ExecutorPtr m_executor;
+ Verifier *m_verifier;
+};
+
+typedef boost::shared_ptr<Wrapper> WrapperPtr;
+
+/**
+ * @brief Namespace holding all exceptions that can be fired by the library
+ */
+namespace Error
+{
+struct ndnOperation : boost::exception, std::exception { };
+}
+
+inline int
+Wrapper::publishData (const Name &name, const Bytes &content, int freshness, const Name &keyName)
+{
+ return publishData(name, head(content), content.size(), freshness, keyName);
+}
+
+inline int
+Wrapper::publishData (const Name &name, const std::string &content, int freshness, const Name &keyName)
+{
+ return publishData(name, reinterpret_cast<const unsigned char *> (content.c_str ()), content.size (), freshness, keyName);
+}
+
+inline int
+Wrapper::publishUnsignedData(const Name &name, const Bytes &content, int freshness)
+{
+ return publishUnsignedData(name, head(content), content.size(), freshness);
+}
+
+inline int
+Wrapper::publishUnsignedData(const Name &name, const std::string &content, int freshness)
+{
+ return publishUnsignedData(name, reinterpret_cast<const unsigned char *> (content.c_str ()), content.size (), freshness);
+}
+
+
+} // ndn
+
+#endif
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 0000000..799e65c
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1,3 @@
+*.bak
+*~
+*~*
diff --git a/doc/doxygen.conf b/doc/doxygen.conf
new file mode 100644
index 0000000..c871541
--- /dev/null
+++ b/doc/doxygen.conf
@@ -0,0 +1,1527 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = "NDN.cxx (C++ NDN API)"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+PROJECT_LOGO = ../doc/ndn.cxx_theme/static/ndn-logo.png
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH = ../..
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = YES
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text "
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE = doxygen.warnings.log
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = doc .
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS = *.h \
+ *.cc
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE = build test
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = build/* test/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH = ../doc/ndn.cxx_theme/static
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER = "sed 's/boost::shared_ptr<\(.*\)>/\1*/'"
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html/doxygen
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER = ../doc/ndn.cxx_theme/ndn.cxx_doxy_header.html
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER = ../doc/ndn.cxx_theme/ndn.cxx_doxy_footer.html
+#HTML_FOOTER = analytics.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET = ../doc/ndn.cxx_theme/static/ndn.cxx_stylesheet.css
+
+HTML_EXTRA_FILES = ../doc/ndn.cxx_theme/static/doxygen.css \
+ ../doc/ndn.cxx_theme/static/bar-top.png \
+ ../doc/ndn.cxx_theme/static/favicon.ico
+
+HTML_COLORSTYLE_HUE = 0
+HTML_COLORSTYLE_SAT = 0
+HTML_COLORSTYLE_GAMMA = 91
+HTML_TIMESTAMP = YES
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = YES
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 300
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = YES
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES = amsmath
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = YES
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = DOXYGEN
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE = doc/ndn.cxx.tag
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/doc/doxygen_boost_dummy.h b/doc/doxygen_boost_dummy.h
new file mode 100644
index 0000000..d15b784
--- /dev/null
+++ b/doc/doxygen_boost_dummy.h
@@ -0,0 +1,5 @@
+namespace boost {
+ template<class T> class shared_ptr { T *ptr; };
+ template<class T> class weak_ptr { T *ptr; };
+}
+
diff --git a/doc/ndn.cxx_theme/ndn.cxx_doxy_footer.html b/doc/ndn.cxx_theme/ndn.cxx_doxy_footer.html
new file mode 100644
index 0000000..53453cd
--- /dev/null
+++ b/doc/ndn.cxx_theme/ndn.cxx_doxy_footer.html
@@ -0,0 +1,31 @@
+<!-- start footer part -->
+<!--BEGIN GENERATE_TREEVIEW-->
+<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
+ <ul>
+ $navpath
+ <li class="footer">$generatedby
+ <a href="http://www.doxygen.org/index.html">
+ <img class="footer" src="$relpath$doxygen.png" alt="doxygen"/></a> $doxygenversion </li>
+ </ul>
+</div>
+<!--END GENERATE_TREEVIEW-->
+<!--BEGIN !GENERATE_TREEVIEW-->
+<hr class="footer"/><address class="footer"><small>
+$generatedby  <a href="http://www.doxygen.org/index.html">
+<img class="footer" src="$relpath$doxygen.png" alt="doxygen"/>
+</a> $doxygenversion
+</small></address>
+<!--END !GENERATE_TREEVIEW-->
+<script>
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+ ga('create', 'UA-21372502-9');
+ ga('send', 'pageview');
+
+</script>
+
+</body>
+</html>
diff --git a/doc/ndn.cxx_theme/ndn.cxx_doxy_header.html b/doc/ndn.cxx_theme/ndn.cxx_doxy_header.html
new file mode 100644
index 0000000..f15135d
--- /dev/null
+++ b/doc/ndn.cxx_theme/ndn.cxx_doxy_header.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<meta http-equiv="X-UA-Compatible" content="IE=9"/>
+<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
+<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+<link href="$relpath$tabs.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="$relpath$jquery.js"></script>
+<script type="text/javascript" src="$relpath$dynsections.js"></script>
+$treeview
+$search
+$mathjax
+<link href="$relpath$doxygen.css" rel="stylesheet" type="text/css"/>
+<link href="$relpath$ndn.cxx_stylesheet.css" rel="stylesheet" type="text/css" />
+<link href="$relpath$favicon.ico" rel="shortcut icon" type="image/ico" />
+</head>
+<body>
+<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
+
+<!--BEGIN TITLEAREA-->
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0" width="100%">
+ <tbody>
+ <tr style="height: 56px;">
+ <td id="projectlogo">
+ <a href="http://www.named-data.net/">
+ <img alt="$projectname Logo" src="../_static/ndn-logo.png"/>
+ </a>
+ <a href="http://irl.cs.ucla.edu/">
+ <img alt="IRL Logo" src="../_static/irl-logo.png"/>
+ </a>
+ </td>
+ <td id="projecttext">
+ <div id="projectbrief">NDN.cxx: C++ NDN API</div>
+ <span id="projectnumber">(CCNx C-API wrapper)</span>
+ </td>
+ <!--BEGIN DISABLE_INDEX-->
+ <!--BEGIN SEARCHENGINE-->
+ <td>$searchbox</td>
+ <!--END SEARCHENGINE-->
+ <!--END DISABLE_INDEX-->
+ <td id="projectsection">
+ <span style="margin-right:10px">API Documentation</span>
+ </td>
+ </tr>
+ </tbody>
+</table>
+</div>
+<!--END TITLEAREA-->
+<!-- end header part -->
diff --git a/doc/ndn.cxx_theme/static/bar-top.png b/doc/ndn.cxx_theme/static/bar-top.png
new file mode 100644
index 0000000..07cafb6
--- /dev/null
+++ b/doc/ndn.cxx_theme/static/bar-top.png
Binary files differ
diff --git a/doc/ndn.cxx_theme/static/bc_s.png b/doc/ndn.cxx_theme/static/bc_s.png
new file mode 100644
index 0000000..eebf862
--- /dev/null
+++ b/doc/ndn.cxx_theme/static/bc_s.png
Binary files differ
diff --git a/doc/ndn.cxx_theme/static/default.css_t b/doc/ndn.cxx_theme/static/default.css_t
new file mode 100644
index 0000000..85c9436
--- /dev/null
+++ b/doc/ndn.cxx_theme/static/default.css_t
@@ -0,0 +1,310 @@
+/*
+ * default.css_t
+ * ~~~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- default theme.
+ *
+ * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+@import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+ font-family: {{ theme_bodyfont }};
+ font-size: 100%;
+ background-color: {{ theme_footerbgcolor }};
+ color: #000;
+ margin: 0;
+ padding: 0;
+}
+
+div.document {
+ background-color: {{ theme_sidebarbgcolor }};
+}
+
+div.documentwrapper {
+ float: left;
+ width: 100%;
+}
+
+div.bodywrapper {
+ margin: 0 0 0 {{ theme_sidebarwidth|toint }}px;
+}
+
+div.body {
+ background-color: {{ theme_bgcolor }};
+ color: {{ theme_textcolor }};
+ padding: 0 20px 30px 20px;
+}
+
+{%- if theme_rightsidebar|tobool %}
+div.bodywrapper {
+ margin: 0 {{ theme_sidebarwidth|toint }}px 0 0;
+}
+{%- endif %}
+
+div.footer {
+ color: {{ theme_footertextcolor }};
+ width: 100%;
+ padding: 9px 0 9px 0;
+ text-align: center;
+ font-size: 75%;
+}
+
+div.footer a {
+ color: {{ theme_footertextcolor }};
+ text-decoration: underline;
+}
+
+div.related {
+ background-color: {{ theme_relbarbgcolor }};
+ line-height: 30px;
+ color: {{ theme_relbartextcolor }};
+}
+
+div.related a {
+ color: {{ theme_relbarlinkcolor }};
+}
+
+div.sphinxsidebar {
+ {%- if theme_stickysidebar|tobool %}
+ top: 30px;
+ bottom: 0;
+ margin: 0;
+ position: fixed;
+ overflow: auto;
+ height: auto;
+ {%- endif %}
+ {%- if theme_rightsidebar|tobool %}
+ float: right;
+ {%- if theme_stickysidebar|tobool %}
+ right: 0;
+ {%- endif %}
+ {%- endif %}
+}
+
+{%- if theme_stickysidebar|tobool %}
+/* this is nice, but it it leads to hidden headings when jumping
+ to an anchor */
+/*
+div.related {
+ position: fixed;
+}
+
+div.documentwrapper {
+ margin-top: 30px;
+}
+*/
+{%- endif %}
+
+div.sphinxsidebar h3 {
+ font-family: {{ theme_headfont }};
+ color: {{ theme_sidebartextcolor }};
+ font-size: 1.4em;
+ font-weight: normal;
+ margin: 0;
+ padding: 0;
+}
+
+div.sphinxsidebar h3 a {
+ color: {{ theme_sidebartextcolor }};
+}
+
+div.sphinxsidebar h4 {
+ font-family: {{ theme_headfont }};
+ color: {{ theme_sidebartextcolor }};
+ font-size: 1.3em;
+ font-weight: normal;
+ margin: 5px 0 0 0;
+ padding: 0;
+}
+
+div.sphinxsidebar p {
+ color: {{ theme_sidebartextcolor }};
+}
+
+div.sphinxsidebar p.topless {
+ margin: 5px 10px 10px 10px;
+}
+
+div.sphinxsidebar ul {
+ margin: 10px;
+ padding: 0;
+ color: {{ theme_sidebartextcolor }};
+}
+
+div.sphinxsidebar a {
+ color: {{ theme_sidebarlinkcolor }};
+}
+
+div.sphinxsidebar input {
+ border: 1px solid {{ theme_sidebarlinkcolor }};
+ font-family: sans-serif;
+ font-size: 1em;
+}
+
+{% if theme_collapsiblesidebar|tobool %}
+/* for collapsible sidebar */
+div#sidebarbutton {
+ background-color: {{ theme_sidebarbtncolor }};
+}
+{% endif %}
+
+/* -- hyperlink styles ------------------------------------------------------ */
+
+a {
+ color: {{ theme_linkcolor }};
+ text-decoration: none;
+}
+
+a:visited {
+ color: {{ theme_visitedlinkcolor }};
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+{% if theme_externalrefs|tobool %}
+a.external {
+ text-decoration: none;
+ border-bottom: 1px dashed {{ theme_linkcolor }};
+}
+
+a.external:hover {
+ text-decoration: none;
+ border-bottom: none;
+}
+
+a.external:visited {
+ text-decoration: none;
+ border-bottom: 1px dashed {{ theme_visitedlinkcolor }};
+}
+{% endif %}
+
+/* -- body styles ----------------------------------------------------------- */
+
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+ font-family: {{ theme_headfont }};
+ background-color: {{ theme_headbgcolor }};
+ font-weight: normal;
+ color: {{ theme_headtextcolor }};
+ border-bottom: 1px solid #ccc;
+ margin: 20px -20px 10px -20px;
+ padding: 3px 0 3px 10px;
+}
+
+div.body h1 { margin-top: 0; font-size: 200%; }
+div.body h2 { font-size: 160%; }
+div.body h3 { font-size: 140%; }
+div.body h4 { font-size: 120%; }
+div.body h5 { font-size: 110%; }
+div.body h6 { font-size: 100%; }
+
+a.headerlink {
+ color: {{ theme_headlinkcolor }};
+ font-size: 0.8em;
+ padding: 0 4px 0 4px;
+ text-decoration: none;
+}
+
+a.headerlink:hover {
+ background-color: {{ theme_headlinkcolor }};
+ color: white;
+}
+
+div.body p, div.body dd, div.body li {
+ text-align: justify;
+ line-height: 130%;
+}
+
+div.admonition p.admonition-title + p {
+ display: inline;
+}
+
+div.admonition p {
+ margin-bottom: 5px;
+}
+
+div.admonition pre {
+ margin-bottom: 5px;
+}
+
+div.admonition ul, div.admonition ol {
+ margin-bottom: 5px;
+}
+
+div.note {
+ background-color: #eee;
+ border: 1px solid #ccc;
+}
+
+div.seealso {
+ background-color: #ffc;
+ border: 1px solid #ff6;
+}
+
+div.topic {
+ background-color: #eee;
+}
+
+div.warning {
+ background-color: #ffe4e4;
+ border: 1px solid #f66;
+}
+
+p.admonition-title {
+ display: inline;
+}
+
+p.admonition-title:after {
+ content: ":";
+}
+
+pre {
+ padding: 5px;
+ background-color: {{ theme_codebgcolor }};
+ color: {{ theme_codetextcolor }};
+ line-height: 120%;
+ border: 1px solid #ac9;
+ border-left: none;
+ border-right: none;
+}
+
+tt {
+ background-color: #ecf0f3;
+ padding: 0 1px 0 1px;
+ font-size: 0.95em;
+}
+
+th {
+ background-color: #ede;
+}
+
+.warning tt {
+ background: #efc2c2;
+}
+
+.note tt {
+ background: #d6d6d6;
+}
+
+.viewcode-back {
+ font-family: {{ theme_bodyfont }};
+}
+
+div.viewcode-block:target {
+ background-color: #f4debf;
+ border-top: 1px solid #ac9;
+ border-bottom: 1px solid #ac9;
+}
diff --git a/doc/ndn.cxx_theme/static/doxygen.css b/doc/ndn.cxx_theme/static/doxygen.css
new file mode 100644
index 0000000..8e096b1
--- /dev/null
+++ b/doc/ndn.cxx_theme/static/doxygen.css
@@ -0,0 +1,1156 @@
+/* The standard CSS for doxygen */
+
+body, table, div, p, dl {
+ font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;
+ font-size: 13px;
+ line-height: 1.3;
+}
+
+/* @group Heading Levels */
+
+h1 {
+ font-size: 150%;
+}
+
+.title {
+ font-size: 150%;
+ font-weight: bold;
+ margin: 10px 2px;
+}
+
+h2 {
+ font-size: 120%;
+}
+
+h3 {
+ font-size: 100%;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ -webkit-transition: text-shadow 0.5s linear;
+ -moz-transition: text-shadow 0.5s linear;
+ -ms-transition: text-shadow 0.5s linear;
+ -o-transition: text-shadow 0.5s linear;
+ transition: text-shadow 0.5s linear;
+ margin-right: 15px;
+}
+
+h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow {
+ text-shadow: 0 0 15px cyan;
+}
+
+dt {
+ font-weight: bold;
+}
+
+div.multicol {
+ -moz-column-gap: 1em;
+ -webkit-column-gap: 1em;
+ -moz-column-count: 3;
+ -webkit-column-count: 3;
+}
+
+p.startli, p.startdd, p.starttd {
+ margin-top: 2px;
+}
+
+p.endli {
+ margin-bottom: 0px;
+}
+
+p.enddd {
+ margin-bottom: 4px;
+}
+
+p.endtd {
+ margin-bottom: 2px;
+}
+
+/* @end */
+
+caption {
+ font-weight: bold;
+}
+
+span.legend {
+ font-size: 70%;
+ text-align: center;
+}
+
+h3.version {
+ font-size: 90%;
+ text-align: center;
+}
+
+div.qindex, div.navtab{
+ background-color: #EFEFEF;
+ border: 1px solid #B5B5B5;
+ text-align: center;
+}
+
+div.qindex, div.navpath {
+ width: 100%;
+ line-height: 140%;
+}
+
+div.navtab {
+ margin-right: 15px;
+}
+
+/* @group Link Styling */
+
+a {
+ color: #585858;
+ font-weight: normal;
+ text-decoration: none;
+}
+
+.contents a:visited {
+ color: #686868;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+a.qindex {
+ font-weight: bold;
+}
+
+a.qindexHL {
+ font-weight: bold;
+ background-color: #B0B0B0;
+ color: #ffffff;
+ border: 1px double #9F9F9F;
+}
+
+.contents a.qindexHL:visited {
+ color: #ffffff;
+}
+
+a.el {
+ font-weight: bold;
+}
+
+a.elRef {
+}
+
+a.code, a.code:visited {
+ color: #4665A2;
+}
+
+a.codeRef, a.codeRef:visited {
+ color: #4665A2;
+}
+
+/* @end */
+
+dl.el {
+ margin-left: -1cm;
+}
+
+pre.fragment {
+ border: 1px solid #C4CFE5;
+ background-color: #FBFCFD;
+ padding: 4px 6px;
+ margin: 4px 8px 4px 2px;
+ overflow: auto;
+ word-wrap: break-word;
+ font-size: 9pt;
+ line-height: 125%;
+ font-family: monospace, fixed;
+ font-size: 105%;
+}
+
+div.fragment {
+ padding: 4px;
+ margin: 4px;
+ background-color: #FCFCFC;
+ border: 1px solid #D0D0D0;
+}
+
+div.line {
+ font-family: monospace, fixed;
+ font-size: 13px;
+ min-height: 13px;
+ line-height: 1.0;
+ text-wrap: unrestricted;
+ white-space: -moz-pre-wrap; /* Moz */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ white-space: pre-wrap; /* CSS3 */
+ word-wrap: break-word; /* IE 5.5+ */
+ text-indent: -53px;
+ padding-left: 53px;
+ padding-bottom: 0px;
+ margin: 0px;
+ -webkit-transition-property: background-color, box-shadow;
+ -webkit-transition-duration: 0.5s;
+ -moz-transition-property: background-color, box-shadow;
+ -moz-transition-duration: 0.5s;
+ -ms-transition-property: background-color, box-shadow;
+ -ms-transition-duration: 0.5s;
+ -o-transition-property: background-color, box-shadow;
+ -o-transition-duration: 0.5s;
+ transition-property: background-color, box-shadow;
+ transition-duration: 0.5s;
+}
+
+div.line.glow {
+ background-color: cyan;
+ box-shadow: 0 0 10px cyan;
+}
+
+
+span.lineno {
+ padding-right: 4px;
+ text-align: right;
+ border-right: 2px solid #0F0;
+ background-color: #E8E8E8;
+ white-space: pre;
+}
+span.lineno a {
+ background-color: #D8D8D8;
+}
+
+span.lineno a:hover {
+ background-color: #C8C8C8;
+}
+
+div.ah {
+ background-color: black;
+ font-weight: bold;
+ color: #ffffff;
+ margin-bottom: 3px;
+ margin-top: 3px;
+ padding: 0.2em;
+ border: solid thin #333;
+ border-radius: 0.5em;
+ -webkit-border-radius: .5em;
+ -moz-border-radius: .5em;
+ box-shadow: 2px 2px 3px #999;
+ -webkit-box-shadow: 2px 2px 3px #999;
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444));
+ background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000);
+}
+
+div.groupHeader {
+ margin-left: 16px;
+ margin-top: 12px;
+ font-weight: bold;
+}
+
+div.groupText {
+ margin-left: 16px;
+ font-style: italic;
+}
+
+body {
+ background-color: white;
+ color: black;
+ margin: 0;
+}
+
+div.contents {
+ margin-top: 10px;
+ margin-left: 12px;
+ margin-right: 8px;
+}
+
+td.indexkey {
+ background-color: #EFEFEF;
+ font-weight: bold;
+ border: 1px solid #D0D0D0;
+ margin: 2px 0px 2px 0;
+ padding: 2px 10px;
+ white-space: nowrap;
+ vertical-align: top;
+}
+
+td.indexvalue {
+ background-color: #EFEFEF;
+ border: 1px solid #D0D0D0;
+ padding: 2px 10px;
+ margin: 2px 0px;
+}
+
+tr.memlist {
+ background-color: #F1F1F1;
+}
+
+p.formulaDsp {
+ text-align: center;
+}
+
+img.formulaDsp {
+
+}
+
+img.formulaInl {
+ vertical-align: middle;
+}
+
+div.center {
+ text-align: center;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ padding: 0px;
+}
+
+div.center img {
+ border: 0px;
+}
+
+address.footer {
+ text-align: right;
+ padding-right: 12px;
+}
+
+img.footer {
+ border: 0px;
+ vertical-align: middle;
+}
+
+/* @group Code Colorization */
+
+span.keyword {
+ color: #008000
+}
+
+span.keywordtype {
+ color: #604020
+}
+
+span.keywordflow {
+ color: #e08000
+}
+
+span.comment {
+ color: #800000
+}
+
+span.preprocessor {
+ color: #806020
+}
+
+span.stringliteral {
+ color: #002080
+}
+
+span.charliteral {
+ color: #008080
+}
+
+span.vhdldigit {
+ color: #ff00ff
+}
+
+span.vhdlchar {
+ color: #000000
+}
+
+span.vhdlkeyword {
+ color: #700070
+}
+
+span.vhdllogic {
+ color: #ff0000
+}
+
+blockquote {
+ background-color: #F8F8F8;
+ border-left: 2px solid #B0B0B0;
+ margin: 0 24px 0 4px;
+ padding: 0 12px 0 16px;
+}
+
+/* @end */
+
+/*
+.search {
+ color: #003399;
+ font-weight: bold;
+}
+
+form.search {
+ margin-bottom: 0px;
+ margin-top: 0px;
+}
+
+input.search {
+ font-size: 75%;
+ color: #000080;
+ font-weight: normal;
+ background-color: #e8eef2;
+}
+*/
+
+td.tiny {
+ font-size: 75%;
+}
+
+.dirtab {
+ padding: 4px;
+ border-collapse: collapse;
+ border: 1px solid #B5B5B5;
+}
+
+th.dirtab {
+ background: #EFEFEF;
+ font-weight: bold;
+}
+
+hr {
+ height: 0px;
+ border: none;
+ border-top: 1px solid #6E6E6E;
+}
+
+hr.footer {
+ height: 1px;
+}
+
+/* @group Member Descriptions */
+
+table.memberdecls {
+ border-spacing: 0px;
+ padding: 0px;
+}
+
+.memberdecls td {
+ -webkit-transition-property: background-color, box-shadow;
+ -webkit-transition-duration: 0.5s;
+ -moz-transition-property: background-color, box-shadow;
+ -moz-transition-duration: 0.5s;
+ -ms-transition-property: background-color, box-shadow;
+ -ms-transition-duration: 0.5s;
+ -o-transition-property: background-color, box-shadow;
+ -o-transition-duration: 0.5s;
+ transition-property: background-color, box-shadow;
+ transition-duration: 0.5s;
+}
+
+.memberdecls td.glow {
+ background-color: cyan;
+ box-shadow: 0 0 15px cyan;
+}
+
+.mdescLeft, .mdescRight,
+.memItemLeft, .memItemRight,
+.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
+ background-color: #FAFAFA;
+ border: none;
+ margin: 4px;
+ padding: 1px 0 0 8px;
+}
+
+.mdescLeft, .mdescRight {
+ padding: 0px 8px 4px 8px;
+ color: #555;
+}
+
+.memItemLeft, .memItemRight, .memTemplParams {
+ border-top: 1px solid #D0D0D0;
+}
+
+.memItemLeft, .memTemplItemLeft {
+ white-space: nowrap;
+}
+
+.memItemRight {
+ width: 100%;
+}
+
+.memTemplParams {
+ color: #686868;
+ white-space: nowrap;
+}
+
+/* @end */
+
+/* @group Member Details */
+
+/* Styles for detailed member documentation */
+
+.memtemplate {
+ font-size: 80%;
+ color: #686868;
+ font-weight: normal;
+ margin-left: 9px;
+}
+
+.memnav {
+ background-color: #EFEFEF;
+ border: 1px solid #B5B5B5;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+
+.mempage {
+ width: 100%;
+}
+
+.memitem {
+ padding: 0;
+ margin-bottom: 10px;
+ margin-right: 5px;
+ -webkit-transition: box-shadow 0.5s linear;
+ -moz-transition: box-shadow 0.5s linear;
+ -ms-transition: box-shadow 0.5s linear;
+ -o-transition: box-shadow 0.5s linear;
+ transition: box-shadow 0.5s linear;
+ display: table !important;
+ width: 100%;
+}
+
+.memitem.glow {
+ box-shadow: 0 0 15px cyan;
+}
+
+.memname {
+ font-weight: bold;
+ margin-left: 6px;
+}
+
+.memname td {
+ vertical-align: bottom;
+}
+
+.memproto, dl.reflist dt {
+ border-top: 1px solid #B9B9B9;
+ border-left: 1px solid #B9B9B9;
+ border-right: 1px solid #B9B9B9;
+ padding: 6px 0px 6px 0px;
+ color: #323232;
+ font-weight: bold;
+ text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
+ background-image:url('nav_f.png');
+ background-repeat:repeat-x;
+ background-color: #E8E8E8;
+ /* opera specific markup */
+ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ border-top-right-radius: 4px;
+ border-top-left-radius: 4px;
+ /* firefox specific markup */
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
+ -moz-border-radius-topright: 4px;
+ -moz-border-radius-topleft: 4px;
+ /* webkit specific markup */
+ -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ -webkit-border-top-right-radius: 4px;
+ -webkit-border-top-left-radius: 4px;
+
+}
+
+.memdoc, dl.reflist dd {
+ border-bottom: 1px solid #B9B9B9;
+ border-left: 1px solid #B9B9B9;
+ border-right: 1px solid #B9B9B9;
+ padding: 6px 10px 2px 10px;
+ background-color: #FCFCFC;
+ border-top-width: 0;
+ background-image:url('nav_g.png');
+ background-repeat:repeat-x;
+ background-color: #FFFFFF;
+ /* opera specific markup */
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ /* firefox specific markup */
+ -moz-border-radius-bottomleft: 4px;
+ -moz-border-radius-bottomright: 4px;
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
+ /* webkit specific markup */
+ -webkit-border-bottom-left-radius: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+ -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+}
+
+dl.reflist dt {
+ padding: 5px;
+}
+
+dl.reflist dd {
+ margin: 0px 0px 10px 0px;
+ padding: 5px;
+}
+
+.paramkey {
+ text-align: right;
+}
+
+.paramtype {
+ white-space: nowrap;
+}
+
+.paramname {
+ color: #602020;
+ white-space: nowrap;
+}
+.paramname em {
+ font-style: normal;
+}
+.paramname code {
+ line-height: 14px;
+}
+
+.params, .retval, .exception, .tparams {
+ margin-left: 0px;
+ padding-left: 0px;
+}
+
+.params .paramname, .retval .paramname {
+ font-weight: bold;
+ vertical-align: top;
+}
+
+.params .paramtype {
+ font-style: italic;
+ vertical-align: top;
+}
+
+.params .paramdir {
+ font-family: "courier new",courier,monospace;
+ vertical-align: top;
+}
+
+table.mlabels {
+ border-spacing: 0px;
+}
+
+td.mlabels-left {
+ width: 100%;
+ padding: 0px;
+}
+
+td.mlabels-right {
+ vertical-align: bottom;
+ padding: 0px;
+ white-space: nowrap;
+}
+
+span.mlabels {
+ margin-left: 8px;
+}
+
+span.mlabel {
+ background-color: #8F8F8F;
+ border-top:1px solid #787878;
+ border-left:1px solid #787878;
+ border-right:1px solid #D0D0D0;
+ border-bottom:1px solid #D0D0D0;
+ text-shadow: none;
+ color: white;
+ margin-right: 4px;
+ padding: 2px 3px;
+ border-radius: 3px;
+ font-size: 7pt;
+ white-space: nowrap;
+}
+
+
+
+/* @end */
+
+/* these are for tree view when not used as main index */
+
+div.directory {
+ margin: 10px 0px;
+ border-top: 1px solid #A8B8D9;
+ border-bottom: 1px solid #A8B8D9;
+ width: 100%;
+}
+
+.directory table {
+ border-collapse:collapse;
+}
+
+.directory td {
+ margin: 0px;
+ padding: 0px;
+ vertical-align: top;
+}
+
+.directory td.entry {
+ white-space: nowrap;
+ padding-right: 6px;
+}
+
+.directory td.entry a {
+ outline:none;
+}
+
+.directory td.entry a img {
+ border: none;
+}
+
+.directory td.desc {
+ width: 100%;
+ padding-left: 6px;
+ padding-right: 6px;
+ border-left: 1px solid rgba(0,0,0,0.05);
+}
+
+.directory tr.even {
+ padding-left: 6px;
+ background-color: #F8F8F8;
+}
+
+.directory img {
+ vertical-align: -30%;
+}
+
+.directory .levels {
+ white-space: nowrap;
+ width: 100%;
+ text-align: right;
+ font-size: 9pt;
+}
+
+.directory .levels span {
+ cursor: pointer;
+ padding-left: 2px;
+ padding-right: 2px;
+ color: #585858;
+}
+
+div.dynheader {
+ margin-top: 8px;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+address {
+ font-style: normal;
+ color: #3A3A3A;
+}
+
+table.doxtable {
+ border-collapse:collapse;
+ margin-top: 4px;
+ margin-bottom: 4px;
+}
+
+table.doxtable td, table.doxtable th {
+ border: 1px solid #3F3F3F;
+ padding: 3px 7px 2px;
+}
+
+table.doxtable th {
+ background-color: #4F4F4F;
+ color: #FFFFFF;
+ font-size: 110%;
+ padding-bottom: 4px;
+ padding-top: 5px;
+}
+
+table.fieldtable {
+ width: 100%;
+ margin-bottom: 10px;
+ border: 1px solid #B9B9B9;
+ border-spacing: 0px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
+ -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);
+ box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);
+}
+
+.fieldtable td, .fieldtable th {
+ padding: 3px 7px 2px;
+}
+
+.fieldtable td.fieldtype, .fieldtable td.fieldname {
+ white-space: nowrap;
+ border-right: 1px solid #B9B9B9;
+ border-bottom: 1px solid #B9B9B9;
+ vertical-align: top;
+}
+
+.fieldtable td.fielddoc {
+ border-bottom: 1px solid #B9B9B9;
+ width: 100%;
+}
+
+.fieldtable tr:last-child td {
+ border-bottom: none;
+}
+
+.fieldtable th {
+ background-image:url('nav_f.png');
+ background-repeat:repeat-x;
+ background-color: #E8E8E8;
+ font-size: 90%;
+ color: #323232;
+ padding-bottom: 4px;
+ padding-top: 5px;
+ text-align:left;
+ -moz-border-radius-topleft: 4px;
+ -moz-border-radius-topright: 4px;
+ -webkit-border-top-left-radius: 4px;
+ -webkit-border-top-right-radius: 4px;
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+ border-bottom: 1px solid #B9B9B9;
+}
+
+
+.tabsearch {
+ top: 0px;
+ left: 10px;
+ height: 36px;
+ background-image: url('tab_b.png');
+ z-index: 101;
+ overflow: hidden;
+ font-size: 13px;
+}
+
+.navpath ul
+{
+ font-size: 11px;
+ background-image:url('tab_b.png');
+ background-repeat:repeat-x;
+ height:30px;
+ line-height:30px;
+ color:#A2A2A2;
+ border:solid 1px #CECECE;
+ overflow:hidden;
+ margin:0px;
+ padding:0px;
+}
+
+.navpath li
+{
+ list-style-type:none;
+ float:left;
+ padding-left:10px;
+ padding-right:15px;
+ background-image:url('bc_s.png');
+ background-repeat:no-repeat;
+ background-position:right;
+ color:#4D4D4D;
+}
+
+.navpath li.navelem a
+{
+ height:32px;
+ display:block;
+ text-decoration: none;
+ outline: none;
+}
+
+.navpath li.navelem a:hover
+{
+ color:#888888;
+}
+
+.navpath li.footer
+{
+ list-style-type:none;
+ float:right;
+ padding-left:10px;
+ padding-right:15px;
+ background-image:none;
+ background-repeat:no-repeat;
+ background-position:right;
+ color:#4D4D4D;
+ font-size: 8pt;
+}
+
+
+div.summary
+{
+ float: right;
+ font-size: 8pt;
+ padding-right: 5px;
+ width: 50%;
+ text-align: right;
+}
+
+div.summary a
+{
+ white-space: nowrap;
+}
+
+div.ingroups
+{
+ font-size: 8pt;
+ width: 50%;
+ text-align: left;
+}
+
+div.ingroups a
+{
+ white-space: nowrap;
+}
+
+div.header
+{
+ background-image:url('nav_h.png');
+ background-repeat:repeat-x;
+ background-color: #FAFAFA;
+ margin: 0px;
+ border-bottom: 1px solid #D0D0D0;
+}
+
+div.headertitle
+{
+ padding: 5px 5px 5px 7px;
+}
+
+dl
+{
+ padding: 0 0 0 10px;
+}
+
+/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */
+dl.section
+{
+ margin-left: 0px;
+ padding-left: 0px;
+}
+
+dl.note
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #D0C000;
+}
+
+dl.warning, dl.attention
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #FF0000;
+}
+
+dl.pre, dl.post, dl.invariant
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #00D000;
+}
+
+dl.deprecated
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #505050;
+}
+
+dl.todo
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #00C0E0;
+}
+
+dl.test
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #3030E0;
+}
+
+dl.bug
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #C08050;
+}
+
+dl.section dd {
+ margin-bottom: 6px;
+}
+
+
+#projectlogo
+{
+ text-align: center;
+ vertical-align: bottom;
+ border-collapse: separate;
+}
+
+#projectlogo img
+{
+ border: 0px none;
+}
+
+#projectname
+{
+ font: 300% Tahoma, Arial,sans-serif;
+ margin: 0px;
+ padding: 2px 0px;
+}
+
+#projectbrief
+{
+ font: 120% Tahoma, Arial,sans-serif;
+ margin: 0px;
+ padding: 0px;
+}
+
+#projectnumber
+{
+ font: 50% Tahoma, Arial,sans-serif;
+ margin: 0px;
+ padding: 0px;
+}
+
+#titlearea
+{
+ padding: 0px;
+ margin: 0px;
+ width: 100%;
+ border-bottom: 1px solid #787878;
+}
+
+.image
+{
+ text-align: center;
+}
+
+.dotgraph
+{
+ text-align: center;
+}
+
+.mscgraph
+{
+ text-align: center;
+}
+
+.caption
+{
+ font-weight: bold;
+}
+
+div.zoom
+{
+ border: 1px solid #A6A6A6;
+}
+
+dl.citelist {
+ margin-bottom:50px;
+}
+
+dl.citelist dt {
+ color:#484848;
+ float:left;
+ font-weight:bold;
+ margin-right:10px;
+ padding:5px;
+}
+
+dl.citelist dd {
+ margin:2px 0;
+ padding:5px 0;
+}
+
+div.toc {
+ padding: 14px 25px;
+ background-color: #F6F6F6;
+ border: 1px solid #DFDFDF;
+ border-radius: 7px 7px 7px 7px;
+ float: right;
+ height: auto;
+ margin: 0 20px 10px 10px;
+ width: 200px;
+}
+
+div.toc li {
+ background: url("bdwn.png") no-repeat scroll 0 5px transparent;
+ font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif;
+ margin-top: 5px;
+ padding-left: 10px;
+ padding-top: 2px;
+}
+
+div.toc h3 {
+ font: bold 12px/1.2 Arial,FreeSans,sans-serif;
+ color: #686868;
+ border-bottom: 0 none;
+ margin: 0;
+}
+
+div.toc ul {
+ list-style: none outside none;
+ border: medium none;
+ padding: 0px;
+}
+
+div.toc li.level1 {
+ margin-left: 0px;
+}
+
+div.toc li.level2 {
+ margin-left: 15px;
+}
+
+div.toc li.level3 {
+ margin-left: 30px;
+}
+
+div.toc li.level4 {
+ margin-left: 45px;
+}
+
+.inherit_header {
+ font-weight: bold;
+ color: gray;
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.inherit_header td {
+ padding: 6px 0px 2px 5px;
+}
+
+.inherit {
+ display: none;
+}
+
+tr.heading h2 {
+ margin-top: 12px;
+ margin-bottom: 4px;
+}
+
+@media print
+{
+ #top { display: none; }
+ #side-nav { display: none; }
+ #nav-path { display: none; }
+ body { overflow:visible; }
+ h1, h2, h3, h4, h5, h6 { page-break-after: avoid; }
+ .summary { display: none; }
+ .memitem { page-break-inside: avoid; }
+ #doc-content
+ {
+ margin-left:0 !important;
+ height:auto !important;
+ width:auto !important;
+ overflow:inherit;
+ display:inline;
+ }
+}
+
diff --git a/doc/ndn.cxx_theme/static/favicon.ico b/doc/ndn.cxx_theme/static/favicon.ico
new file mode 100644
index 0000000..ae2eabc
--- /dev/null
+++ b/doc/ndn.cxx_theme/static/favicon.ico
Binary files differ
diff --git a/doc/ndn.cxx_theme/static/irl-logo.png b/doc/ndn.cxx_theme/static/irl-logo.png
new file mode 100644
index 0000000..9e6f87f
--- /dev/null
+++ b/doc/ndn.cxx_theme/static/irl-logo.png
Binary files differ
diff --git a/doc/ndn.cxx_theme/static/nav_f.png b/doc/ndn.cxx_theme/static/nav_f.png
new file mode 100644
index 0000000..f09ac2f
--- /dev/null
+++ b/doc/ndn.cxx_theme/static/nav_f.png
Binary files differ
diff --git a/doc/ndn.cxx_theme/static/ndn-logo.png b/doc/ndn.cxx_theme/static/ndn-logo.png
new file mode 100644
index 0000000..1ccee4a
--- /dev/null
+++ b/doc/ndn.cxx_theme/static/ndn-logo.png
Binary files differ
diff --git a/doc/ndn.cxx_theme/static/ndn.cxx_stylesheet.css b/doc/ndn.cxx_theme/static/ndn.cxx_stylesheet.css
new file mode 100644
index 0000000..c900197
--- /dev/null
+++ b/doc/ndn.cxx_theme/static/ndn.cxx_stylesheet.css
@@ -0,0 +1,131 @@
+/* ns-3 changes to the default CSS from Doxygen and Sphinx */
+
+body, table, div, p, dl {
+ font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;
+ font-size: 12px;
+ color: black;
+}
+
+a {
+ color: #91A501;
+ font-weight: bold;
+}
+
+/* Sphinx headings */
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+ background-image: url('nav_f.png');
+}
+
+/* Doxygen side bar */
+#nav-tree {
+ font-size: 12px;
+}
+
+#nav-tree a {
+ font-weight: normal;
+}
+
+/* Sphinx nav links bar (relbar) */
+div.related {
+ background-image:url('tab_b.png')
+}
+
+div.related h3 {
+ display: none;
+}
+
+div.related a {
+ color: #91A501;
+ font-size: 14px;
+ font-weight: bold;
+}
+
+div.related li {
+ background-image: url('bc_s.png');
+ background-position: 100% 40%;
+ background-repeat: no-repeat;
+ padding-left: 10px;
+ padding-right: 15px;
+}
+
+div.related li.right {
+ background-image: none;
+ padding-left: 0px;
+ padding-right: 0px;
+}
+
+/* Sphinx side bar */
+div.sphinxsidebar {
+ font-size: 12px;
+}
+
+div.sphinxsidebar a {
+ font-weight: normal;
+}
+
+
+/* Title bar elements */
+
+#titlearea
+{
+ background-image:url('bar-top.png');
+ background-repeat:repeat;
+ border-bottom: 1px solid #5B5B5B;
+ color: white;
+}
+
+#projectlogo
+{
+ text-align: center;
+ margin: 10px;
+ vertical-align: middle;
+ width: 220px;
+ color: white;
+}
+
+#projecttext
+{
+ align: left;
+ padding-left: 2em;
+ font-color:white;
+}
+
+#projectbrief
+{
+ font: 120% Tahoma, Arial,sans-serif;
+ margin: 0px;
+ padding: 0px;
+ color: white;
+}
+
+#projectnumber
+{
+ font: 100% Tahoma, Arial,sans-serif;
+ margin: 0px;
+ padding: 0px;
+ color: white;
+}
+
+#projectsection
+{
+ text-align: right;
+ font: 24pt Aldo, Tahoma, Arial,sans-serif;
+ margin: 10px;
+ margin-right: 10px;
+ vertical-align: middle;
+ color: white;
+}
+
+.highlight .hll {
+ background-color: #FFFF88;
+}
+
+.red {
+ color: red;
+ font-weight: bold;
+}
\ No newline at end of file
diff --git a/doc/ndn.cxx_theme/static/sidebar.js b/doc/ndn.cxx_theme/static/sidebar.js
new file mode 100644
index 0000000..a45e192
--- /dev/null
+++ b/doc/ndn.cxx_theme/static/sidebar.js
@@ -0,0 +1,151 @@
+/*
+ * sidebar.js
+ * ~~~~~~~~~~
+ *
+ * This script makes the Sphinx sidebar collapsible.
+ *
+ * .sphinxsidebar contains .sphinxsidebarwrapper. This script adds
+ * in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton
+ * used to collapse and expand the sidebar.
+ *
+ * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden
+ * and the width of the sidebar and the margin-left of the document
+ * are decreased. When the sidebar is expanded the opposite happens.
+ * This script saves a per-browser/per-session cookie used to
+ * remember the position of the sidebar among the pages.
+ * Once the browser is closed the cookie is deleted and the position
+ * reset to the default (expanded).
+ *
+ * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+$(function() {
+ // global elements used by the functions.
+ // the 'sidebarbutton' element is defined as global after its
+ // creation, in the add_sidebar_button function
+ var bodywrapper = $('.bodywrapper');
+ var sidebar = $('.sphinxsidebar');
+ var sidebarwrapper = $('.sphinxsidebarwrapper');
+
+ // for some reason, the document has no sidebar; do not run into errors
+ if (!sidebar.length) return;
+
+ // original margin-left of the bodywrapper and width of the sidebar
+ // with the sidebar expanded
+ var bw_margin_expanded = bodywrapper.css('margin-left');
+ var ssb_width_expanded = sidebar.width();
+
+ // margin-left of the bodywrapper and width of the sidebar
+ // with the sidebar collapsed
+ var bw_margin_collapsed = '.8em';
+ var ssb_width_collapsed = '.8em';
+
+ // colors used by the current theme
+ var dark_color = $('.related').css('background-color');
+ var light_color = $('.document').css('background-color');
+
+ function sidebar_is_collapsed() {
+ return sidebarwrapper.is(':not(:visible)');
+ }
+
+ function toggle_sidebar() {
+ if (sidebar_is_collapsed())
+ expand_sidebar();
+ else
+ collapse_sidebar();
+ }
+
+ function collapse_sidebar() {
+ sidebarwrapper.hide();
+ sidebar.css('width', ssb_width_collapsed);
+ bodywrapper.css('margin-left', bw_margin_collapsed);
+ sidebarbutton.css({
+ 'margin-left': '0',
+ 'height': bodywrapper.height()
+ });
+ sidebarbutton.find('span').text('»');
+ sidebarbutton.attr('title', _('Expand sidebar'));
+ document.cookie = 'sidebar=collapsed';
+ }
+
+ function expand_sidebar() {
+ bodywrapper.css('margin-left', bw_margin_expanded);
+ sidebar.css('width', ssb_width_expanded);
+ sidebarwrapper.show();
+ sidebarbutton.css({
+ 'margin-left': ssb_width_expanded-12,
+ 'height': bodywrapper.height()
+ });
+ sidebarbutton.find('span').text('«');
+ sidebarbutton.attr('title', _('Collapse sidebar'));
+ document.cookie = 'sidebar=expanded';
+ }
+
+ function add_sidebar_button() {
+ sidebarwrapper.css({
+ 'float': 'left',
+ 'margin-right': '0',
+ 'width': ssb_width_expanded - 28
+ });
+ // create the button
+ sidebar.append(
+ '<div id="sidebarbutton"><span>«</span></div>'
+ );
+ var sidebarbutton = $('#sidebarbutton');
+ light_color = sidebarbutton.css('background-color');
+ // find the height of the viewport to center the '<<' in the page
+ var viewport_height;
+ if (window.innerHeight)
+ viewport_height = window.innerHeight;
+ else
+ viewport_height = $(window).height();
+ sidebarbutton.find('span').css({
+ 'display': 'block',
+ 'margin-top': (viewport_height - sidebar.position().top - 20) / 2
+ });
+
+ sidebarbutton.click(toggle_sidebar);
+ sidebarbutton.attr('title', _('Collapse sidebar'));
+ sidebarbutton.css({
+ 'color': '#FFFFFF',
+ 'border-left': '1px solid ' + dark_color,
+ 'font-size': '1.2em',
+ 'cursor': 'pointer',
+ 'height': bodywrapper.height(),
+ 'padding-top': '1px',
+ 'margin-left': ssb_width_expanded - 12
+ });
+
+ sidebarbutton.hover(
+ function () {
+ $(this).css('background-color', dark_color);
+ },
+ function () {
+ $(this).css('background-color', light_color);
+ }
+ );
+ }
+
+ function set_position_from_cookie() {
+ if (!document.cookie)
+ return;
+ var items = document.cookie.split(';');
+ for(var k=0; k<items.length; k++) {
+ var key_val = items[k].split('=');
+ var key = key_val[0];
+ if (key == 'sidebar') {
+ var value = key_val[1];
+ if ((value == 'collapsed') && (!sidebar_is_collapsed()))
+ collapse_sidebar();
+ else if ((value == 'expanded') && (sidebar_is_collapsed()))
+ expand_sidebar();
+ }
+ }
+ }
+
+ add_sidebar_button();
+ var sidebarbutton = $('#sidebarbutton');
+ set_position_from_cookie();
+});
diff --git a/doc/ndn.cxx_theme/static/tab_b.png b/doc/ndn.cxx_theme/static/tab_b.png
new file mode 100644
index 0000000..801fb4e
--- /dev/null
+++ b/doc/ndn.cxx_theme/static/tab_b.png
Binary files differ
diff --git a/doc/ndn.cxx_theme/theme.conf b/doc/ndn.cxx_theme/theme.conf
new file mode 100644
index 0000000..55be315
--- /dev/null
+++ b/doc/ndn.cxx_theme/theme.conf
@@ -0,0 +1,53 @@
+[theme]
+inherit = basic
+stylesheet = default.css
+pygments_style = sphinx
+
+[options]
+projectname = ndnSIM
+homepage = http://www.named-data.net/
+homepage2 = http://irl.cs.ucla.edu/
+apidocs = ndnSIM API
+apidocsurl = http://?????????/doxygen/annotated.html
+customstylesheet = ndn.cxx-stylesheet.css
+logo = ndn-logo.png
+logo2 = irl-logo.png
+logoalt = ns-3 Logo
+projectbrief = NDN.cxx: C++ NDN API
+projectnumber = (CCNx C-API wrapper)
+
+favicon = favicon.ico
+docstitle = Documentation
+
+rightsidebar = false
+stickysidebar = false
+collapsiblesidebar = true
+externalrefs = true
+
+bgcolor = white
+textcolor = black
+linkcolor = #91A501
+visitedlinkcolor = #91A501
+
+headbgcolor = #E3E3E3
+headtextcolor = #373737
+headlinkcolor = #91A501
+
+relbarbgcolor = #D5D5D5
+relbarlinkcolor = #373737
+relbartextcolor = #373737
+
+sidebarbgcolor = #FAFAFA
+sidebartextcolor = #373737
+sidebarlinkcolor = #91A501
+sidebarbtncolor = #D5D5D5
+
+footerbgcolor = #D5D5D5
+footertextcolor = #364D7C
+
+codebgcolor = ##FBFCFD
+codetextcolor = black
+
+bodyfont = 'Lucida Grande', Verdana, Geneva, Arial, sans-serif
+headfont = 'Lucida Grande', Verdana, Geneva, Arial, sans-serif
+
diff --git a/doc/source/conf.py b/doc/source/conf.py
new file mode 100644
index 0000000..f2d4413
--- /dev/null
+++ b/doc/source/conf.py
@@ -0,0 +1,243 @@
+# -*- coding: utf-8 -*-
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = [ "sphinx.ext.autodoc", "sphinx.ext.mathjax", "sphinxcontrib.doxylink", "sphinxcontrib.aafig", "sphinxcontrib.googleanalytics", "sphinxcontrib.bibtex" ]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u''
+copyright = u'2012-2013 (c) Alexander Afanasyev, Zhenkai Zhu'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '0.4'
+# The full version, including alpha/beta/rc tags.
+release = 'NDN.cxx'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = []
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'ndn.cxx_theme'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+html_theme_path = ["../"]
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+html_domain_indices = False
+
+# If false, no index is generated.
+html_use_index = False
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+html_file_suffix = ".html"
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'ndn.cxx'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'ndn.cxx.tex', u'NDN.cxx (C++ NDN API)',
+ u'Alexander Afanasyev and Zhenkai Zhu', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+latex_domain_indices = False
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'ndn.cxx', u'NDN.cxx (C++ NDN API)',
+ [u'Alexander Afanasyev and Zhenkai Zhu'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'ndn.cxx', u'NDN.cxx (C++ NDN API)',
+ u'Alexander Afanasyev and Zhenkai Zhu', 'ndn.cxx', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+texinfo_domain_indices = False
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+doxylink = {
+ 'ndn' : ('build/doc/ndn.cxx.tag', 'doxygen/'),
+}
+
+googleanalytics_id = "UA-21372502-9"
+
+googleanalytics_enabled = True
+
+# aafig_format = dict(latex='pdf', html='png', text=None)
+
+# aafig_default_options = dict(Fixed=True)
diff --git a/doc/source/index.rst b/doc/source/index.rst
new file mode 100644
index 0000000..977fd7a
--- /dev/null
+++ b/doc/source/index.rst
@@ -0,0 +1,11 @@
+.. NDN.cxx: C++ NDN API
+
+NDN.cxx: C++ NDN API
+====================
+
+Contents:
+.. intro
+
+.. toctree::
+ :maxdepth: 4
+
diff --git a/doc/uml.vpp b/doc/uml.vpp
new file mode 100644
index 0000000..3414251
--- /dev/null
+++ b/doc/uml.vpp
Binary files differ
diff --git a/doc/visual-paradigm-8.vpp b/doc/visual-paradigm-8.vpp
new file mode 100644
index 0000000..ccd61a0
--- /dev/null
+++ b/doc/visual-paradigm-8.vpp
Binary files differ
diff --git a/example/.gitignore b/example/.gitignore
new file mode 100644
index 0000000..8ed876c
--- /dev/null
+++ b/example/.gitignore
@@ -0,0 +1,2 @@
+build/
+.waf*
diff --git a/example/client.cc b/example/client.cc
new file mode 100644
index 0000000..279d260
--- /dev/null
+++ b/example/client.cc
@@ -0,0 +1,72 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include <ndn.cxx.h>
+#include <iostream>
+
+using namespace std;
+
+const char *FILENAME = NULL;
+ndn::Name InterestBaseName;
+
+// create a global handler
+ndn::Wrapper handler;
+
+void OnData (ndn::Name name, ndn::PcoPtr pco);
+void OnTimeout (ndn::Name name, const ndn::Closure &closure, ndn::InterestPtr origInterest);
+
+void OnData (ndn::Name name, ndn::PcoPtr pco)
+{
+ ndn::BytesPtr content = pco->contentPtr ();
+ cout << string ((char*)ndn::head (*content), content->size ());
+
+ int seqnum = ndn::Name::asSeqNum (*name.rbegin ());
+ if (seqnum >= 10)
+ {
+ return;
+ }
+
+ cerr << ">> C++ " << ndn::Name (InterestBaseName).appendSeqNum (seqnum + 1) << endl; // a shortcut to construct name
+ handler.sendInterest (ndn::Interest ()
+ .setName (ndn::Name (InterestBaseName).appendSeqNum (seqnum + 1))
+ .setScope (ndn::Interest::SCOPE_LOCAL_HOST),
+ ndn::Closure (OnData, OnTimeout));
+}
+
+void OnTimeout (ndn::Name name, const ndn::Closure &closure, ndn::InterestPtr origInterest)
+{
+ // re-express interest
+ handler.sendInterest (*origInterest, closure);
+}
+
+int
+main (int argc, char **argv)
+{
+ if (argc < 2)
+ {
+ std::cerr << "You have to specify filename as an argument" << std::endl;
+ return -1;
+ }
+
+ // this code does not check for most of the bad conditions
+ FILENAME = argv[1];
+
+ InterestBaseName = ndn::Name ("/my-local-prefix/simple-fetch/file");
+ InterestBaseName.append (FILENAME);
+
+ cerr << ">> C++ " << ndn::Name (InterestBaseName).appendSeqNum (0) << endl;
+ handler.sendInterest (ndn::Interest ()
+ .setName (ndn::Name (InterestBaseName).appendSeqNum (0))
+ .setScope (ndn::Interest::SCOPE_LOCAL_HOST),
+ ndn::Closure (OnData, OnTimeout));
+
+ sleep (3);
+ return 0;
+}
diff --git a/example/server.cc b/example/server.cc
new file mode 100644
index 0000000..1a62f20
--- /dev/null
+++ b/example/server.cc
@@ -0,0 +1,45 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include <ndn.cxx.h>
+#include <iostream>
+
+using namespace std;
+
+ndn::Name InterestBaseName;
+
+// create a global handler
+ndn::Wrapper handler;
+
+void OnInterest (ndn::InterestPtr interest)
+{
+ cerr << interest->getName () << endl;
+
+ static int COUNTER = 0;
+
+ ostringstream os;
+ os << "C++ LINE #" << (COUNTER++) << endl;
+
+ handler.publishData (interest->getName (), os.str (), 5);
+}
+
+int
+main (int argc, char **argv)
+{
+ InterestBaseName = ndn::Name ("ccnx:/my-local-prefix/simple-fetch/file");
+
+ handler.setInterestFilter (InterestBaseName, OnInterest);
+
+ while (true)
+ {
+ sleep (1);
+ }
+ return 0;
+}
diff --git a/example/waf b/example/waf
new file mode 100755
index 0000000..f26d925
--- /dev/null
+++ b/example/waf
Binary files differ
diff --git a/example/wscript b/example/wscript
new file mode 100644
index 0000000..c617d47
--- /dev/null
+++ b/example/wscript
@@ -0,0 +1,66 @@
+# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+VERSION='0.1'
+APPNAME='test-project'
+
+from waflib import Build, Logs, Utils, Task, TaskGen, Configure
+
+def options(opt):
+ opt.load('compiler_c compiler_cxx boost ccnx')
+
+def configure(conf):
+ conf.load("compiler_c compiler_cxx ccnx")
+
+ conf.add_supported_cxxflags (cxxflags = ['-O0',
+ '-Wall',
+ '-Wno-unused-variable',
+ '-g3',
+ '-Wno-unused-private-field',
+ '-fcolor-diagnostics',
+ '-Qunused-arguments'
+ ])
+
+ if not conf.check_cfg(package='openssl', args=['--cflags', '--libs'], uselib_store='SSL', mandatory=False):
+ libcrypto = conf.check_cc(lib='crypto',
+ header_name='openssl/crypto.h',
+ define_name='HAVE_SSL',
+ uselib_store='SSL')
+ else:
+ conf.define ("HAVE_SSL", 1)
+ if not conf.get_define ("HAVE_SSL"):
+ conf.fatal ("Cannot find SSL libraries")
+
+ conf.check_ccnx (path=conf.options.ccnx_dir)
+ conf.check_cfg(package='libndn.cxx', args=['--cflags', '--libs'], uselib_store='CCNXCPP', mandatory=True)
+
+ conf.load('boost')
+ conf.check_boost(lib='system test iostreams filesystem thread')
+
+def build (bld):
+ bld (
+ features = ["cxx", "cxxprogram"],
+ target = "client",
+ source = "client.cc",
+ use = 'BOOST BOOST_THREAD CCNX CCNXCPP',
+ )
+
+ bld (
+ features = ["cxx", "cxxprogram"],
+ target = "server",
+ source = "server.cc",
+ use = 'BOOST BOOST_THREAD CCNX CCNXCPP',
+ )
+
+@Configure.conf
+def add_supported_cxxflags(self, cxxflags):
+ """
+ Check which cxxflags are supported by compiler and add them to env.CXXFLAGS variable
+ """
+ self.start_msg('Checking allowed flags for c++ compiler')
+
+ supportedFlags = []
+ for flag in cxxflags:
+ if self.check_cxx (cxxflags=[flag], mandatory=False):
+ supportedFlags += [flag]
+
+ self.end_msg (' '.join (supportedFlags))
+ self.env.CXXFLAGS += supportedFlags
diff --git a/executor/executor.cc b/executor/executor.cc
new file mode 100644
index 0000000..87b5760
--- /dev/null
+++ b/executor/executor.cc
@@ -0,0 +1,129 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "executor.h"
+#include "logging.h"
+
+INIT_LOGGER("Executor")
+
+using namespace std;
+using namespace boost;
+
+Executor::Executor (int poolSize)
+ : m_needStop (true)
+ , m_poolSize (poolSize)
+{
+}
+
+Executor::~Executor()
+{
+ _LOG_DEBUG ("Enter destructor");
+ shutdown ();
+ _LOG_DEBUG ("Exit destructor");
+}
+
+void
+Executor::start ()
+{
+ if (m_needStop)
+ {
+ m_needStop = false;
+ for (int i = 0; i < m_poolSize; i++)
+ {
+ m_group.create_thread (bind(&Executor::run, this));
+ }
+ }
+}
+
+void
+Executor::shutdown ()
+{
+ if (!m_needStop)
+ {
+ m_needStop = true;
+ _LOG_DEBUG ("Iterrupting all");
+ m_group.interrupt_all ();
+ _LOG_DEBUG ("Join all");
+ m_group.join_all ();
+ }
+}
+
+
+void
+Executor::execute(const Job &job)
+{
+ _LOG_DEBUG ("Add to job queue");
+
+ Lock lock(m_mutex);
+ bool queueWasEmpty = m_queue.empty ();
+ m_queue.push_back(job);
+
+ // notify working threads if the queue was empty
+ if (queueWasEmpty)
+ {
+ m_cond.notify_one ();
+ }
+}
+
+int
+Executor::poolSize()
+{
+ return m_group.size();
+}
+
+int
+Executor::jobQueueSize()
+{
+ Lock lock(m_mutex);
+ return m_queue.size();
+}
+
+void
+Executor::run ()
+{
+ _LOG_DEBUG ("Start thread");
+
+ while(!m_needStop)
+ {
+ Job job = waitForJob();
+
+ _LOG_DEBUG (">>> enter job");
+ job (); // even if job is "null", nothing bad will happen
+ _LOG_DEBUG ("<<< exit job");
+ }
+
+ _LOG_DEBUG ("Executor thread finished");
+}
+
+Executor::Job
+Executor::waitForJob()
+{
+ Lock lock(m_mutex);
+
+ // wait until job queue is not empty
+ while (m_queue.empty())
+ {
+ _LOG_DEBUG ("Unlocking mutex for wait");
+ m_cond.wait(lock);
+ _LOG_DEBUG ("Re-locking mutex after wait");
+ }
+
+ _LOG_DEBUG ("Got signal on condition");
+
+ Job job;
+ if (!m_queue.empty ()) // this is not always guaranteed, especially after interruption from destructor
+ {
+ job = m_queue.front();
+ m_queue.pop_front();
+ }
+ return job;
+}
diff --git a/executor/executor.h b/executor/executor.h
new file mode 100644
index 0000000..dd9eac3
--- /dev/null
+++ b/executor/executor.h
@@ -0,0 +1,80 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef EXECUTOR_H
+#define EXECUTOR_H
+
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread/condition_variable.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/locks.hpp>
+#include <boost/thread/thread.hpp>
+#include <deque>
+
+/* A very simple executor to execute submitted tasks immediately or
+ * in the future (depending on whether there is idle thread)
+ * A fixed number of threads are created for executing tasks;
+ * The policy is FIFO
+ * No cancellation of submitted tasks
+ */
+
+class Executor
+{
+public:
+ typedef boost::function<void ()> Job;
+
+ Executor(int poolSize);
+ ~Executor();
+
+ // execute the job immediately or sometime in the future
+ void
+ execute(const Job &job);
+
+ int
+ poolSize();
+
+// only for test
+ int
+ jobQueueSize();
+
+ void
+ start ();
+
+ void
+ shutdown ();
+
+private:
+ void
+ run();
+
+ Job
+ waitForJob();
+
+private:
+ typedef std::deque<Job> JobQueue;
+ typedef boost::mutex Mutex;
+ typedef boost::unique_lock<Mutex> Lock;
+ typedef boost::condition_variable Cond;
+ typedef boost::thread Thread;
+ typedef boost::thread_group ThreadGroup;
+ JobQueue m_queue;
+ Mutex m_mutex;
+ Cond m_cond;
+ ThreadGroup m_group;
+
+ volatile bool m_needStop;
+ int m_poolSize;
+};
+
+typedef boost::shared_ptr<Executor> ExecutorPtr;
+#endif // EXECUTOR_H
diff --git a/libndn.cxx.pc.in b/libndn.cxx.pc.in
new file mode 100644
index 0000000..e880ea7
--- /dev/null
+++ b/libndn.cxx.pc.in
@@ -0,0 +1,9 @@
+prefix=@PREFIX@
+libdir=@LIBDIR@
+includedir=@INCLUDEDIR@
+
+Name: libccnx-cpp
+Description: C++ NDN API (currently a wrapper on top of CCNx C library)
+Version: @VERSION@
+Libs: -L${libdir} -lndn.cxx
+Cflags: -I${includedir}
diff --git a/log4cxx.properties b/log4cxx.properties
new file mode 100644
index 0000000..bdbc1a2
--- /dev/null
+++ b/log4cxx.properties
@@ -0,0 +1,24 @@
+# Set root logger level to DEBUG and its only appender to A1.
+log4j.rootLogger=TRACE, A1
+#, rollingFile
+
+# A1 is set to be a ConsoleAppender.
+log4j.appender.A1=org.apache.log4j.ConsoleAppender
+
+# A1 uses PatternLayout.
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.target=System.err
+#log4j.appender.A1.layout.ConversionPattern=%d{dd-MMM HH:MM:SS,SSS} %p %c %m%n
+#log4j.appender.A1.layout.ConversionPattern=%d{hh:mm:ss,SSS} %-14t %-14c %m%n
+log4j.appender.A1.layout.ConversionPattern=%d{ss,SSS} %-5p %-12c %m%n
+
+log4j.appender.rollingFile=org.apache.log4j.RollingFileAppender
+log4j.appender.rollingFile.File=logfile.txt
+log4j.appender.rollingFile.MaxFileSize=10MB
+log4j.appender.rollingFile.MaxBackupIndex=9
+log4j.appender.rollingFile.layout = org.apache.log4j.PatternLayout
+log4j.appender.rollingFile.layout.ConversionPattern=%d{ss,SSS} %-5p %-12c %m%n
+
+log4j.logger.Executor = ERROR
+#log4j.logger.Scheduler = ERROR
+
diff --git a/logging.cc b/logging.cc
new file mode 100644
index 0000000..04fb6c3
--- /dev/null
+++ b/logging.cc
@@ -0,0 +1,51 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ * Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#include "logging.h"
+
+#ifdef HAVE_LOG4CXX
+
+#include <log4cxx/logger.h>
+#include <log4cxx/basicconfigurator.h>
+#include <log4cxx/consoleappender.h>
+#include <log4cxx/patternlayout.h>
+#include <log4cxx/level.h>
+#include <log4cxx/propertyconfigurator.h>
+#include <log4cxx/defaultconfigurator.h>
+#include <log4cxx/helpers/exception.h>
+using namespace log4cxx;
+using namespace log4cxx::helpers;
+
+#include <unistd.h>
+
+void
+INIT_LOGGERS ()
+{
+ static bool configured = false;
+
+ if (configured) return;
+
+ if (access ("log4cxx.properties", R_OK)==0)
+ PropertyConfigurator::configureAndWatch ("log4cxx.properties");
+ else
+ {
+ PatternLayoutPtr layout (new PatternLayout ("%d{HH:mm:ss} %p %c{1} - %m%n"));
+ ConsoleAppenderPtr appender (new ConsoleAppender (layout));
+
+ BasicConfigurator::configure( appender );
+ Logger::getRootLogger()->setLevel (log4cxx::Level::getInfo ());
+ }
+
+ configured = true;
+}
+
+#endif
diff --git a/logging.h b/logging.h
new file mode 100644
index 0000000..2aa3344
--- /dev/null
+++ b/logging.h
@@ -0,0 +1,84 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ * Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#ifndef LOGGING_H
+#define LOGGING_H
+
+#include "config.h"
+
+#ifdef HAVE_LOG4CXX
+
+#include <log4cxx/logger.h>
+
+#define MEMBER_LOGGER \
+ static log4cxx::LoggerPtr staticModuleLogger;
+
+#define INIT_MEMBER_LOGGER(className,name) \
+ log4cxx::LoggerPtr className::staticModuleLogger = log4cxx::Logger::getLogger (name);
+
+#define INIT_LOGGER(name) \
+ static log4cxx::LoggerPtr staticModuleLogger = log4cxx::Logger::getLogger (name);
+
+#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__ << "()");
+
+#define _LOG_ERROR(x) \
+ LOG4CXX_ERROR(staticModuleLogger, x);
+
+#define _LOG_ERROR_COND(cond,x) \
+ if (cond) { _LOG_ERROR(x) }
+
+#define _LOG_DEBUG_COND(cond,x) \
+ if (cond) { _LOG_DEBUG(x) }
+
+void
+INIT_LOGGERS ();
+
+#else // else HAVE_LOG4CXX
+
+#define INIT_LOGGER(name)
+#define _LOG_FUNCTION(x)
+#define _LOG_FUNCTION_NOARGS
+#define _LOG_TRACE(x)
+#define INIT_LOGGERS(x)
+#define _LOG_ERROR(x)
+#define _LOG_ERROR_COND(cond,x)
+#define _LOG_DEBUG_COND(cond,x)
+
+#define MEMBER_LOGGER
+#define INIT_MEMBER_LOGGER(className,name)
+
+#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 << std::endl;
+
+#else
+#define _LOG_DEBUG(x)
+#endif
+
+#endif // HAVE_LOG4CXX
+
+#endif // LOGGING_H
diff --git a/ndn-cpp.h b/ndn-cpp.h
new file mode 100644
index 0000000..72a1db9
--- /dev/null
+++ b/ndn-cpp.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 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>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_CXX_ALL_H
+#define NDN_CXX_ALL_H
+
+#include <ndn.cxx/common.h>
+#include <ndn.cxx/wrapper.h>
+
+#include <ndn.cxx/interest.h>
+#include <ndn.cxx/pco.h>
+
+#include <ndn.cxx/closure.h>
+
+// #include <ndn.cxx/cert.h>
+// #include <ndn.cxx/charbuf.h>
+// #include <ndn.cxx/discovery.h>
+// #include <ndn.cxx/verifier.h>
+
+#endif
diff --git a/ndn-cpp/common.h b/ndn-cpp/common.h
new file mode 100644
index 0000000..e45f067
--- /dev/null
+++ b/ndn-cpp/common.h
@@ -0,0 +1,221 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_COMMON_H
+#define NDN_COMMON_H
+
+#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+namespace ndn
+{
+template<class T>
+struct Ptr : public boost::shared_ptr<T>
+{
+ Ptr () { }
+ Ptr (boost::shared_ptr<T> ptr) : boost::shared_ptr<T>(ptr) { }
+ Ptr (T *ptr) : boost::shared_ptr<T>(ptr) { }
+
+ template<class Y>
+ Ptr & operator = (boost::shared_ptr<Y> ptr)
+ {
+ boost::static_pointer_cast<T> (ptr).swap (*this);
+ // *this = boost::static_pointer_cast<T> (ptr);
+ return *this;
+ }
+
+ operator Ptr<const T> () const { return *this; }
+
+ static Ptr
+ Create () { return boost::make_shared<T> (); }
+};
+
+typedef boost::posix_time::ptime Time;
+typedef boost::posix_time::time_duration TimeInterval;
+
+namespace time
+{
+inline TimeInterval Seconds (int secs) { return boost::posix_time::seconds (secs); }
+inline TimeInterval Milliseconds (int msecs) { return boost::posix_time::milliseconds (msecs); }
+inline TimeInterval Microseconds (int musecs) { return boost::posix_time::microseconds (musecs); }
+
+inline TimeInterval Seconds (double fractionalSeconds)
+{
+ double seconds, microseconds;
+ seconds = std::modf (fractionalSeconds, µseconds);
+ microseconds *= 1000000;
+
+ return time::Seconds((int)seconds) + time::Microseconds((int)microseconds);
+}
+
+inline Time Now () { return boost::posix_time::microsec_clock::universal_time (); }
+
+const Time UNIX_EPOCH_TIME = Time (boost::gregorian::date (1970, boost::gregorian::Jan, 1));
+inline TimeInterval NowUnixTimestamp ()
+{
+ return TimeInterval (time::Now () - UNIX_EPOCH_TIME);
+}
+} // time
+} // ndn
+
+
+extern "C" {
+#include <ccn/ccn.h>
+#include <ccn/charbuf.h>
+#include <ccn/keystore.h>
+#include <ccn/uri.h>
+#include <ccn/bloom.h>
+#include <ccn/signing.h>
+}
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include <boost/exception/all.hpp>
+#include <boost/function.hpp>
+#include <string>
+#include <sstream>
+#include <map>
+#include <utility>
+#include <string.h>
+#include <boost/iostreams/filter/gzip.hpp>
+#include <boost/iostreams/filtering_stream.hpp>
+#include <boost/iostreams/device/back_inserter.hpp>
+#include <boost/range/iterator_range.hpp>
+#include <boost/make_shared.hpp>
+
+namespace ndn {
+typedef std::vector<unsigned char> Bytes;
+typedef std::vector<std::string>Comps;
+
+typedef boost::shared_ptr<Bytes> BytesPtr;
+
+inline
+const unsigned char *
+head(const Bytes &bytes)
+{
+ return &bytes[0];
+}
+
+inline
+unsigned char *
+head (Bytes &bytes)
+{
+ return &bytes[0];
+}
+
+// --- Bytes operations start ---
+inline void
+readRaw(Bytes &bytes, const unsigned char *src, size_t len)
+{
+ if (len > 0)
+ {
+ bytes.resize(len);
+ memcpy (head (bytes), src, len);
+ }
+}
+
+inline BytesPtr
+readRawPtr (const unsigned char *src, size_t len)
+{
+ if (len > 0)
+ {
+ BytesPtr ret (new Bytes (len));
+ memcpy (head (*ret), src, len);
+
+ return ret;
+ }
+ else
+ return BytesPtr ();
+}
+
+template<class Msg>
+BytesPtr
+serializeMsg(const Msg &msg)
+{
+ int size = msg.ByteSize ();
+ BytesPtr bytes (new Bytes (size));
+ msg.SerializeToArray (head(*bytes), size);
+ return bytes;
+}
+
+template<class Msg>
+boost::shared_ptr<Msg>
+deserializeMsg (const Bytes &bytes)
+{
+ boost::shared_ptr<Msg> retval (new Msg ());
+ if (!retval->ParseFromArray (head (bytes), bytes.size ()))
+ {
+ // to indicate an error
+ return boost::shared_ptr<Msg> ();
+ }
+ return retval;
+}
+
+template<class Msg>
+boost::shared_ptr<Msg>
+deserializeMsg (const void *buf, size_t length)
+{
+ boost::shared_ptr<Msg> retval (new Msg ());
+ if (!retval->ParseFromArray (buf, length))
+ {
+ // to indicate an error
+ return boost::shared_ptr<Msg> ();
+ }
+ return retval;
+}
+
+
+template<class Msg>
+BytesPtr
+serializeGZipMsg(const Msg &msg)
+{
+ std::vector<char> bytes; // Bytes couldn't work
+ {
+ boost::iostreams::filtering_ostream out;
+ out.push(boost::iostreams::gzip_compressor()); // gzip filter
+ out.push(boost::iostreams::back_inserter(bytes)); // back_inserter sink
+
+ msg.SerializeToOstream(&out);
+ }
+ BytesPtr uBytes = boost::make_shared<Bytes>(bytes.size());
+ memcpy(&(*uBytes)[0], &bytes[0], bytes.size());
+ return uBytes;
+}
+
+template<class Msg>
+boost::shared_ptr<Msg>
+deserializeGZipMsg(const Bytes &bytes)
+{
+ std::vector<char> sBytes(bytes.size());
+ memcpy(&sBytes[0], &bytes[0], bytes.size());
+ boost::iostreams::filtering_istream in;
+ in.push(boost::iostreams::gzip_decompressor()); // gzip filter
+ in.push(boost::make_iterator_range(sBytes)); // source
+
+ boost::shared_ptr<Msg> retval = boost::make_shared<Msg>();
+ if (!retval->ParseFromIstream(&in))
+ {
+ // to indicate an error
+ return boost::shared_ptr<Msg> ();
+ }
+
+ return retval;
+}
+
+
+// --- Bytes operations end ---
+
+// Exceptions
+typedef boost::error_info<struct tag_errmsg, std::string> error_info_str;
+
+} // ndn
+#endif // NDN_COMMON_H
diff --git a/ndn-cpp/data.cc b/ndn-cpp/data.cc
new file mode 100644
index 0000000..5a44da8
--- /dev/null
+++ b/ndn-cpp/data.cc
@@ -0,0 +1,23 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "data.h"
+
+namespace ndn {
+
+Data::Data ()
+{
+}
+
+Data::~Data ()
+{
+}
+
+} // namespace ndn
diff --git a/ndn-cpp/data.h b/ndn-cpp/data.h
new file mode 100644
index 0000000..212dfbd
--- /dev/null
+++ b/ndn-cpp/data.h
@@ -0,0 +1,204 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_DATA_H
+#define NDN_DATA_H
+
+#include "ndn-cpp/fields/name.h"
+#include "ndn-cpp/fields/content.h"
+#include "ndn-cpp/fields/signature.h"
+#include "ndn-cpp/fields/signed-blob.h"
+
+namespace ndn {
+
+/**
+ * @brief Class implementing abstractions to work with NDN Data packets
+ */
+class Data
+{
+public:
+ /**
+ * @brief Create an empty Data with empty payload
+ **/
+ Data ();
+
+ /**
+ * @brief Destructor
+ */
+ ~Data ();
+
+ /**
+ * @brief Set data packet name
+ * @param name name of the data packet
+ * @return reference to self (to allow method chaining)
+ *
+ * In some cases, a direct access to and manipulation of name using getName is more efficient
+ */
+ inline Data &
+ setName (const Name &name);
+
+ /**
+ * @brief Get data packet name (const reference)
+ * @returns name of the data packet
+ */
+ inline const Name &
+ getName () const;
+
+ /**
+ * @brief Get data packet name (reference)
+ * @returns name of the data packet
+ */
+ inline Name &
+ getName ();
+
+ /**
+ * @brief Get const smart pointer to signature object
+ */
+ inline Ptr<const Signature>
+ getSignature () const;
+
+ /**
+ * @brief Get smart pointer to signature object
+ */
+ inline Ptr<Signature>
+ getSignature ();
+
+ /**
+ * @brief Set signature object
+ * @param signature smart pointer to a signature object
+ */
+ inline void
+ setSignature (Ptr<Signature> sigature);
+
+ /**
+ * @brief Get const reference to content object (content info + actual content)
+ */
+ inline const Content &
+ getContent () const;
+
+ /**
+ * @brief Get reference to content object (content info + actual content)
+ */
+ inline Content &
+ getContent ();
+
+ /**
+ * @brief Set content object (content info + actual content)
+ * @param content reference to a content object
+ *
+ * More efficient way (that avoids copying):
+ * @code
+ * Content content (...);
+ * getContent ().swap (content);
+ * @endcode
+ */
+ inline void
+ setContent (const Content &content);
+
+ /**
+ * @brief A helper method to directly access actual content data (const reference)
+ *
+ * This method is equivalent to
+ * @code
+ * getContent ().getContent ()
+ * @endcode
+ */
+ inline const Blob &
+ content () const;
+
+ /**
+ * @brief A helper method to directly access actual content data (reference)
+ *
+ * This method is equivalent to
+ * @code
+ * getContent ().getContent ()
+ * @endcode
+ */
+ inline Blob &
+ content ();
+
+private:
+ Name m_name;
+ Ptr<Signature> m_signature; // signature with its parameters "binds" name and content
+ Content m_content;
+
+ Ptr<SignedBlob> m_wire;
+};
+
+inline Data &
+Data::setName (const Name &name)
+{
+ m_name = name;
+ return *this;
+}
+
+inline const Name &
+Data::getName () const
+{
+ return m_name;
+}
+
+inline Name &
+Data::getName ()
+{
+ return m_name;
+}
+
+inline Ptr<const Signature>
+Data::getSignature () const
+{
+ return m_signature;
+}
+
+inline Ptr<Signature>
+Data::getSignature ()
+{
+ return m_signature;
+}
+
+inline void
+Data::setSignature (Ptr<Signature> signature)
+{
+ m_signature = signature;
+}
+
+inline const Content &
+Data::getContent () const
+{
+ return m_content;
+}
+
+inline Content &
+Data::getContent ()
+{
+ return m_content;
+}
+
+inline void
+Data::setContent (const Content &content)
+{
+ m_content = content;
+}
+
+inline const Blob &
+Data::content () const
+{
+ return getContent ().getContent ();
+}
+
+inline Blob &
+Data::content ()
+{
+ return getContent ().getContent ();
+}
+
+} // namespace ndn
+
+#endif // NDN_DATA_H
diff --git a/ndn-cpp/error.h b/ndn-cpp/error.h
new file mode 100644
index 0000000..d6379c6
--- /dev/null
+++ b/ndn-cpp/error.h
@@ -0,0 +1,119 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+/**
+ * @file error.h
+ * @brief This file defines basic elements for the library reporting
+ *
+ * The library throws a number of exceptions.
+ * In general, the following example shows how to print out diagnostic information
+ * when one of the exceptions is thrown
+ * @code
+ * try
+ * {
+ * ... operations with ndn::Name
+ * }
+ * catch (boost::exception &e)
+ * {
+ * std::cerr << boost::diagnostic_information (e) << std::endl;
+ * }
+ * @endcode
+ */
+
+#ifndef NDN_ERROR_H
+#define NDN_ERROR_H
+
+#include <boost/exception/all.hpp>
+
+namespace ndn
+{
+namespace error
+{
+
+struct Error : public virtual boost::exception, public virtual std::exception {}; ///< @brief Some error with error reporting engine
+struct Uri : public virtual boost::exception, public virtual std::exception {}; ///< @brief An error with URI processing
+struct StringTransform : public virtual boost::exception, public virtual std::exception {};
+struct Name : public virtual boost::exception, public virtual std::exception {}; ///< @brief An error with Name
+namespace name {
+struct Component : public virtual boost::exception, public virtual std::exception {}; ///< @brief An error with name::Component
+}
+struct Exclude : public virtual boost::exception, public virtual std::exception {}; ///< @brief An error with Exclude
+struct KeyLocator : public virtual boost::exception, public virtual std::exception {}; ///< @brief An error with KeyLocator
+namespace wire {
+struct Ccnb : public virtual boost::exception, public virtual std::exception {}; ///< @brief An error with wire::Ccnb encoding
+}
+struct Keychain : public virtual boost::exception, public virtual std::exception {}; ///< @brief An error with security::Keychain
+
+// Diagnostic information fields
+
+/**
+ * @brief Free-formatted text message explaining the error
+ *
+ * @code
+ * ...
+ * catch (boost::exception &e)
+ * {
+ * if (const std::string *error = boost::get_error_info<error::msg> (e))
+ * ...
+ * }
+ * @endcode
+ *
+ * @see get_msg
+ */
+typedef boost::error_info<struct tag_msg, std::string> msg;
+
+/**
+ * @brief Helper method to get error message from the exception
+ *
+ * Method assumes that message is present, if not, an exception will be thrown
+ */
+inline const std::string &
+get_msg (boost::exception &e)
+{
+ const std::string *error = boost::get_error_info<msg> (e);
+ if (error == 0)
+ BOOST_THROW_EXCEPTION (Error ());
+ return *error;
+}
+
+/**
+ * @brief Report of the position of the error (error-specific meaning)
+ *
+ * @code
+ * ...
+ * catch (boost::exception &e)
+ * {
+ * if (const int *error = boost::get_error_info<error::pos> (e))
+ * ...
+ * }
+ * @endcode
+ *
+ * @see get_pos
+ */
+typedef boost::error_info<struct tag_pos, int> pos;
+
+/**
+ * @brief Helper method to get position of the error from the exception
+ *
+ * Method assumes that position is present, if not, an exception will be thrown
+ */
+inline int
+get_pos (boost::exception &e)
+{
+ const int *position = boost::get_error_info<pos> (e);
+ if (position == 0)
+ BOOST_THROW_EXCEPTION (Error ());
+ return *position;
+}
+
+} // error
+} // ndn
+
+#endif // NDN_ERROR_H
diff --git a/ndn-cpp/face.cc b/ndn-cpp/face.cc
new file mode 100644
index 0000000..455f283
--- /dev/null
+++ b/ndn-cpp/face.cc
@@ -0,0 +1,118 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "face.h"
+
+namespace ndn {
+
+Face::sent_interest
+Face::sendInterest (Ptr<const Interest> interest, const SatisfiedInterestCallback &dataCallback)
+{
+ // magic to be done in child class
+
+ sent_interest item = m_sentInterests.find_exact (interest->getName ());
+ if (item == m_sentInterests.end ())
+ {
+ std::pair<sent_interest, bool> insertRes =
+ m_sentInterests.insert (interest->getName (), Ptr<sent_interest_container::payload_traits::payload_type>::Create ());
+
+ item = insertRes.first;
+ }
+ item->payload ()->push_back (dataCallback);
+
+ return item;
+}
+
+void
+Face::clearInterest (Face::sent_interest interest)
+{
+ m_sentInterests.erase (interest);
+}
+
+Face::registered_prefix
+Face::setInterestFilter (Ptr<const Name> prefix, const ExpectedInterestCallback &interestCallback)
+{
+ // magic to be done in child class
+
+ registered_prefix item = m_registeredPrefixes.find_exact (*prefix);
+ if (item == m_registeredPrefixes.end ())
+ {
+ std::pair<registered_prefix, bool> insertRes =
+ m_registeredPrefixes.insert (*prefix, Ptr<registered_prefix_container::payload_traits::payload_type>::Create ());
+
+ item = insertRes.first;
+ }
+ item->payload ()->push_back (interestCallback);
+
+ return item;
+}
+
+void
+Face::clearInterestFilter (const Name &prefix)
+{
+ registered_prefix item = m_registeredPrefixes.find_exact (prefix);
+ if (item == m_registeredPrefixes.end ())
+ return;
+
+ clearInterestFilter (item);
+}
+
+void
+Face::clearInterestFilter (Face::registered_prefix filter)
+{
+ m_registeredPrefixes.erase (filter);
+}
+
+} // ndn
+
+// void
+// CcnxWrapper::OnInterest (const Ptr<const ndn::Interest> &interest, Ptr<Packet> packet)
+// {
+// ndn::App::OnInterest (interest, packet);
+
+// // the app cannot set several filters for the same prefix
+// CcnxFilterEntryContainer<InterestCallback>::iterator entry = m_interestCallbacks.longest_prefix_match (interest->GetName ());
+// if (entry == m_interestCallbacks.end ())
+// {
+// _LOG_DEBUG ("No Interest callback set");
+// return;
+// }
+
+// entry->payload ()->m_callback (lexical_cast<string> (interest->GetName ()));
+// }
+
+// void
+// CcnxWrapper::OnContentObject (const Ptr<const ndn::ContentObject> &contentObject,
+// Ptr<Packet> payload)
+// {
+// ndn::App::OnContentObject (contentObject, payload);
+// NS_LOG_DEBUG ("<< D " << contentObject->GetName ());
+
+// CcnxFilterEntryContainer<RawDataCallback>::iterator entry = m_dataCallbacks.longest_prefix_match (contentObject->GetName ());
+// if (entry == m_dataCallbacks.end ())
+// {
+// _LOG_DEBUG ("No Data callback set");
+// return;
+// }
+
+// while (entry != m_dataCallbacks.end ())
+// {
+// ostringstream content;
+// payload->CopyData (&content, payload->GetSize ());
+
+// entry->payload ()->m_callback (lexical_cast<string> (contentObject->GetName ()), content.str ().c_str (), content.str ().size ());
+
+// m_dataCallbacks.erase (entry);
+
+// entry = m_dataCallbacks.longest_prefix_match (contentObject->GetName ());
+// }
+// }
+
+// }
diff --git a/ndn-cpp/face.h b/ndn-cpp/face.h
new file mode 100644
index 0000000..38a618c
--- /dev/null
+++ b/ndn-cpp/face.h
@@ -0,0 +1,70 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_CXX_H
+#define NDN_CXX_H
+
+#include "ndn-cpp/common.h"
+#include "ndn-cpp/fields/name.h"
+#include "ndn-cpp/interest.h"
+#include "ndn-cpp/data.h"
+
+#include "trie/trie-with-policy.h"
+#include "trie/policies/counting-policy.h"
+
+#include <list>
+
+namespace ndn {
+
+template<class Callback>
+struct CallbackTable :
+ public trie::trie_with_policy< Name,
+ trie::ptr_payload_traits< std::list<Callback> >,
+ trie::counting_policy_traits >
+{
+};
+
+
+class Face
+{
+public:
+ typedef boost::function<void (Ptr<Data> incomingData, Ptr<const Interest> satisfiedInterest)> SatisfiedInterestCallback;
+ typedef boost::function<void (Ptr<Interest> incomingInterest, Ptr<const Name> registeredPrefix)> ExpectedInterestCallback;
+
+ // some internal definitions
+ typedef CallbackTable< SatisfiedInterestCallback > sent_interest_container;
+ typedef CallbackTable< ExpectedInterestCallback > registered_prefix_container;
+
+ typedef sent_interest_container::iterator sent_interest;
+ typedef registered_prefix_container::iterator registered_prefix;
+
+ sent_interest
+ sendInterest (Ptr<const Interest> interest, const SatisfiedInterestCallback &dataCallback);
+
+ void
+ clearInterest (sent_interest interest);
+
+ registered_prefix
+ setInterestFilter (Ptr<const Name> prefix, const ExpectedInterestCallback &interestCallback);
+
+ void
+ clearInterestFilter (const Name &prefix);
+
+ void
+ clearInterestFilter (registered_prefix filter);
+
+private:
+ sent_interest_container m_sentInterests;
+ registered_prefix_container m_registeredPrefixes;
+};
+
+} // ndn
+
+#endif // NDN_CXX_H
diff --git a/ndn-cpp/fields/blob.h b/ndn-cpp/fields/blob.h
new file mode 100644
index 0000000..85fd71b
--- /dev/null
+++ b/ndn-cpp/fields/blob.h
@@ -0,0 +1,60 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_BLOB_H
+#define NDN_BLOB_H
+
+#include <vector>
+#include <cstddef>
+
+namespace ndn {
+
+/**
+ * @brief Class representing a general-use binary blob
+ */
+class Blob : public std::vector<char>
+{
+public:
+ /**
+ * @brief Creates an empty blob
+ */
+ Blob ()
+ {
+ }
+
+ Blob (const void *buf, size_t length)
+ : std::vector<char> (reinterpret_cast<const char*> (buf), reinterpret_cast<const char*> (buf) + length)
+ {
+ }
+
+ /**
+ * @brief Get pointer to the first byte of the binary blob
+ */
+ inline char*
+ buf ()
+ {
+ return &front ();
+ }
+
+ /**
+ * @brief Get const pointer to the first byte of the binary blob
+ */
+ inline const char*
+ buf () const
+ {
+ return &front ();
+ }
+};
+
+} // ndn
+
+#endif // NDN_BLOB_H
diff --git a/ndn-cpp/fields/content.cc b/ndn-cpp/fields/content.cc
new file mode 100644
index 0000000..0216bd2
--- /dev/null
+++ b/ndn-cpp/fields/content.cc
@@ -0,0 +1,53 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "content.h"
+#include "ndn-cpp/error.h"
+
+namespace ndn
+{
+
+const name::Component Content::noFinalBlock = name::Component ();
+const TimeInterval Content::noFreshness;
+const TimeInterval Content::maxFreshness = time::Seconds (2147);
+
+Content::Content ()
+{
+}
+
+Content::Content (const void *buffer, size_t size,
+ const Time ×tamp,
+ Type type/* = DATA*/,
+ const TimeInterval &freshness/* = maxFreshness*/,
+ const name::Component &finalBlock/* = noFinalBlock*/)
+ : m_timestamp (timestamp)
+ , m_type (type)
+ , m_freshness (freshness)
+ , m_finalBlockId (finalBlock)
+
+ , m_content (buffer, size)
+{
+}
+
+Content::Content (const void *buffer, size_t size,
+ Type type/* = DATA*/,
+ const TimeInterval &freshness/* = maxFreshness*/,
+ const name::Component &finalBlock/* = noFinalBlock*/)
+ : m_timestamp (time::Now ())
+ , m_type (type)
+ , m_freshness (freshness)
+ , m_finalBlockId (finalBlock)
+
+ , m_content (buffer, size)
+{
+}
+
+
+} // ndn
diff --git a/ndn-cpp/fields/content.h b/ndn-cpp/fields/content.h
new file mode 100644
index 0000000..752f24c
--- /dev/null
+++ b/ndn-cpp/fields/content.h
@@ -0,0 +1,306 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_CONTENT_H
+#define NDN_CONTENT_H
+
+#include "ndn-cpp/common.h"
+#include "ndn-cpp/fields/blob.h"
+#include "ndn-cpp/fields/name-component.h"
+
+namespace ndn {
+
+/**
+ * @brief Class providing an interface to work with content NDN data packets
+ *
+ * Content of data packets consists of two parts: information about content
+ * (timestamp, freshness, type, etc.) and raw content itself
+ *
+ * @code
+ * Content ::= ContentInfo
+ * ContentData
+ *
+ * ContentInfo ::= Timestamp
+ * Type?
+ * Freshness?
+ * FinalBlockID?
+ * @endcode
+ */
+class Content
+{
+public:
+ /**
+ * @brief Enum of content types
+ */
+ enum Type
+ {
+ DATA = 0, ///< @brief No semantics is defined for the content
+ ENCR, ///< @brief Indicate that the content is encrypted
+ GONE, ///< @brief ?
+ KEY, ///< @brief Content is a key object
+ LINK, ///< @brief Content contains a LINK object
+ NACK ///< @brief Negative acknowledgment by the content producer, indicating that there is no data with the requested name
+ };
+
+ /**
+ * @brief Create an empty content
+ */
+ Content ();
+
+ /**
+ * @brief Create a content from a memory buffer
+ * @param buffer pointer to first byte of the memory buffer
+ * @param size size of the memory buffer
+ * @param timestamp content generation timestamp
+ * @param type type of content (default is Content::DATA)
+ * @param freshness amount of time the content is considered "fresh" (default is 2147 seconds, maximum possible value for CCNx)
+ * @param finalBlock name of the final DATA
+ *
+ * Use the other version of the constructor, if timestamp needs to be automatically generated
+ */
+ Content (const void *buffer, size_t size,
+ const Time ×tamp,
+ Type type = DATA,
+ const TimeInterval &freshness = maxFreshness,
+ const name::Component &finalBlock = noFinalBlock);
+
+ /**
+ * @brief Create a content from a memory buffer
+ * @param buffer pointer to first byte of the memory buffer
+ * @param size size of the memory buffer
+ * @param type type of content (default is Content::DATA)
+ * @param freshness amount of time the content is considered "fresh" (default is 2147 seconds, maximum possible value for CCNx)
+ * @param finalBlock name of the final DATA
+ *
+ * This method automatically sets timestamp of the created content to the current time (UTC clock)
+ */
+ Content (const void *buffer, size_t size,
+ Type type = DATA,
+ const TimeInterval &freshness = maxFreshness,
+ const name::Component &finalBlock = noFinalBlock);
+
+ /**
+ * @brief Get content timestamp (const reference)
+ */
+ inline const Time &
+ getTimestamp () const;
+
+ /**
+ * @brief Get content timestamp (reference)
+ */
+ inline Time &
+ getTimestamp ();
+
+ /**
+ * @brief Set content timestamp
+ * @param timestamp content timestamp (default is empty ptime object)
+ *
+ * If parameter is omitted, then the current time (UTC clock) is used
+ */
+ inline void
+ setTimeStamp (const Time ×tamp = Time ());
+
+ /**
+ * @brief Get type of content
+ */
+ inline Type
+ getType () const;
+
+ /**
+ * @brief Set type of content
+ * @param type content type @see Content::Type
+ */
+ inline void
+ setType (Type type);
+
+ /**
+ * @brief Get content freshness (const reference)
+ */
+ inline const TimeInterval &
+ getFreshness () const;
+
+ /**
+ * @brief Get content freshness (reference)
+ */
+ inline TimeInterval &
+ getFreshness ();
+
+ /**
+ * @brief Set content freshness
+ * @param freshness content freshness (default value is Content::maxFreshness = 2147 seconds)
+ */
+ inline void
+ setFreshness (const TimeInterval &freshness = maxFreshness);
+
+ /**
+ * @brief Get final block ID of the content (const reference)
+ */
+ inline const name::Component &
+ getFinalBlockId () const;
+
+ /**
+ * @brief Get final block ID of the content (reference)
+ */
+ inline name::Component &
+ getFinalBlockId ();
+
+ /**
+ * @brief Set final block ID of the content
+ * @param finalBlock component name of the final block
+ */
+ inline void
+ setFinalBlockId (const name::Component &finalBlock);
+
+ /**
+ * @brief Get const reference to content bits
+ */
+ inline const Blob &
+ getContent () const;
+
+ /**
+ * @brief Get reference to content bits
+ */
+ inline Blob &
+ getContent ();
+
+ /**
+ * @brief Set content bits from blob
+ * @param content blob that holds content bits
+ *
+ * In certain cases, getContent ().swap (content); is more appropriate,
+ * since it would avoid object copying
+ */
+ inline void
+ setContent (const Blob &content);
+
+ /**
+ * @brief Set content bits from memory buffer
+ * @param buf pointer to first byte of memory buffer
+ * @param length size of memory buffer
+ */
+ inline void
+ setContent (const void *buf, size_t length);
+
+public:
+ static const name::Component noFinalBlock; ///< @brief Not a final block == name::Component ()
+ static const TimeInterval noFreshness; ///< @brief Minimum freshness == seconds (0)
+ static const TimeInterval maxFreshness; ///< @brief Maximum freshnes == seconds (2147)
+
+private:
+ // ContentInfo
+ Time m_timestamp;
+ Type m_type;
+ TimeInterval m_freshness;
+ name::Component m_finalBlockId;
+
+ // ContentData
+ Blob m_content;
+};
+
+inline const Time &
+Content::getTimestamp () const
+{
+ return m_timestamp;
+}
+
+inline Time &
+Content::getTimestamp ()
+{
+ return m_timestamp;
+}
+
+inline void
+Content::setTimeStamp (const Time ×tamp/* = Time ()*/)
+{
+ if (timestamp != Time ())
+ {
+ m_timestamp = timestamp;
+ }
+ else
+ {
+ m_timestamp = time::Now ();
+ }
+}
+
+inline Content::Type
+Content::getType () const
+{
+ return m_type;
+}
+
+inline void
+Content::setType (Content::Type type)
+{
+ m_type = type;
+}
+
+inline const TimeInterval &
+Content::getFreshness () const
+{
+ return m_freshness;
+}
+
+inline TimeInterval &
+Content::getFreshness ()
+{
+ return m_freshness;
+}
+
+inline void
+Content::setFreshness (const TimeInterval &freshness/* = Content::maxFreshness*/)
+{
+ m_freshness = freshness;
+}
+
+inline const name::Component &
+Content::getFinalBlockId () const
+{
+ return m_finalBlockId;
+}
+
+inline name::Component &
+Content::getFinalBlockId ()
+{
+ return m_finalBlockId;
+}
+
+inline void
+Content::setFinalBlockId (const name::Component &finalBlock)
+{
+ m_finalBlockId = finalBlock;
+}
+
+inline const Blob &
+Content::getContent () const
+{
+ return m_content;
+}
+
+inline Blob &
+Content::getContent ()
+{
+ return m_content;
+}
+
+inline void
+Content::setContent (const Blob &content)
+{
+ m_content = content;
+}
+
+inline void
+Content::setContent (const void *buf, size_t length)
+{
+ Blob (buf, length).swap (m_content);
+}
+
+} // ndn
+
+#endif // NDN_SIGNATURE_H
diff --git a/ndn-cpp/fields/exclude.cc b/ndn-cpp/fields/exclude.cc
new file mode 100644
index 0000000..b637c01
--- /dev/null
+++ b/ndn-cpp/fields/exclude.cc
@@ -0,0 +1,168 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "exclude.h"
+
+#include "ndn-cpp/error.h"
+
+namespace ndn
+{
+
+Exclude::Exclude ()
+{
+}
+
+// example: ANY /b /d ANY /f
+//
+// ordered in map as:
+//
+// /f (false); /d (true); /b (false); / (true)
+//
+// lower_bound (/) -> / (true) <-- excluded (equal)
+// lower_bound (/a) -> / (true) <-- excluded (any)
+// lower_bound (/b) -> /b (false) <--- excluded (equal)
+// lower_bound (/c) -> /b (false) <--- not excluded (not equal and no ANY)
+// lower_bound (/d) -> /d (true) <- excluded
+// lower_bound (/e) -> /d (true) <- excluded
+bool
+Exclude::isExcluded (const name::Component &comp) const
+{
+ const_iterator lowerBound = m_exclude.lower_bound (comp);
+ if (lowerBound == end ())
+ return false;
+
+ if (lowerBound->second)
+ return true;
+ else
+ return lowerBound->first == comp;
+
+ return false;
+}
+
+Exclude &
+Exclude::excludeOne (const name::Component &comp)
+{
+ if (!isExcluded (comp))
+ {
+ m_exclude.insert (std::make_pair (comp, false));
+ }
+ return *this;
+}
+
+
+// example: ANY /b0 /d0 ANY /f0
+//
+// ordered in map as:
+//
+// /f0 (false); /d0 (true); /b0 (false); / (true)
+//
+// lower_bound (/) -> / (true) <-- excluded (equal)
+// lower_bound (/a0) -> / (true) <-- excluded (any)
+// lower_bound (/b0) -> /b0 (false) <--- excluded (equal)
+// lower_bound (/c0) -> /b0 (false) <--- not excluded (not equal and no ANY)
+// lower_bound (/d0) -> /d0 (true) <- excluded
+// lower_bound (/e0) -> /d0 (true) <- excluded
+
+
+// examples with desired outcomes
+// excludeRange (/, /f0) -> ANY /f0
+// /f0 (false); / (true)
+// excludeRange (/, /f1) -> ANY /f1
+// /f1 (false); / (true)
+// excludeRange (/a0, /e0) -> ANY /f0
+// /f0 (false); / (true)
+// excludeRange (/a0, /e0) -> ANY /f0
+// /f0 (false); / (true)
+
+// excludeRange (/b1, /c0) -> ANY /b0 /b1 ANY /c0 /d0 ANY /f0
+// /f0 (false); /d0 (true); /c0 (false); /b1 (true); /b0 (false); / (true)
+
+Exclude &
+Exclude::excludeRange (const name::Component &from, const name::Component &to)
+{
+ if (from >= to)
+ {
+ BOOST_THROW_EXCEPTION (error::Exclude ()
+ << error::msg ("Invalid exclude range (for single name exclude use Exclude::excludeOne)")
+ << error::msg (from.toUri ())
+ << error::msg (to.toUri ()));
+ }
+
+ iterator newFrom = m_exclude.lower_bound (from);
+ if (newFrom == end () || !newFrom->second /*without ANY*/)
+ {
+ std::pair<iterator, bool> fromResult = m_exclude.insert (std::make_pair (from, true));
+ newFrom = fromResult.first;
+ if (!fromResult.second)
+ {
+ // this means that the lower bound is equal to the item itself. So, just update ANY flag
+ newFrom->second = true;
+ }
+ }
+ // else
+ // nothing special if start of the range already exists with ANY flag set
+
+ iterator newTo = m_exclude.lower_bound (to); // !newTo cannot be end ()
+ if (newTo == newFrom || !newTo->second)
+ {
+ std::pair<iterator, bool> toResult = m_exclude.insert (std::make_pair (to, false));
+ newTo = toResult.first;
+ ++ newTo;
+ }
+ else
+ {
+ // nothing to do really
+ }
+
+ m_exclude.erase (newTo, newFrom); // remove any intermediate node, since all of the are excluded
+
+ return *this;
+}
+
+Exclude &
+Exclude::excludeAfter (const name::Component &from)
+{
+ iterator newFrom = m_exclude.lower_bound (from);
+ if (newFrom == end () || !newFrom->second /*without ANY*/)
+ {
+ std::pair<iterator, bool> fromResult = m_exclude.insert (std::make_pair (from, true));
+ newFrom = fromResult.first;
+ if (!fromResult.second)
+ {
+ // this means that the lower bound is equal to the item itself. So, just update ANY flag
+ newFrom->second = true;
+ }
+ }
+ // else
+ // nothing special if start of the range already exists with ANY flag set
+
+ if (newFrom != m_exclude.begin ())
+ {
+ m_exclude.erase (m_exclude.begin (), newFrom); // remove any intermediate node, since all of the are excluded
+ }
+
+ return *this;
+}
+
+
+std::ostream&
+operator << (std::ostream &os, const Exclude &exclude)
+{
+ for (Exclude::const_reverse_iterator i = exclude.rbegin (); i != exclude.rend (); i++)
+ {
+ os << i->first.toUri () << " ";
+ if (i->second)
+ os << "----> ";
+ }
+ return os;
+}
+
+
+} // ndn
diff --git a/ndn-cpp/fields/exclude.h b/ndn-cpp/fields/exclude.h
new file mode 100644
index 0000000..265a809
--- /dev/null
+++ b/ndn-cpp/fields/exclude.h
@@ -0,0 +1,169 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_EXCLUDE_H
+#define NDN_EXCLUDE_H
+
+#include "ndn-cpp/fields/name-component.h"
+
+#include <map>
+
+namespace ndn {
+
+/**
+ * @brief Class to represent Exclude component in NDN interests
+ */
+class Exclude
+{
+public:
+ typedef std::map< name::Component, bool /*any*/, std::greater<name::Component> > exclude_type;
+
+ typedef exclude_type::iterator iterator;
+ typedef exclude_type::const_iterator const_iterator;
+ typedef exclude_type::reverse_iterator reverse_iterator;
+ typedef exclude_type::const_reverse_iterator const_reverse_iterator;
+
+ /**
+ * @brief Default constructor an empty exclude
+ */
+ Exclude ();
+
+ /**
+ * @brief Check if name component is excluded
+ * @param comp Name component to check against exclude filter
+ */
+ bool
+ isExcluded (const name::Component &comp) const;
+
+ /**
+ * @brief Exclude specific name component
+ * @param comp component to exclude
+ * @returns *this to allow chaining
+ */
+ Exclude &
+ excludeOne (const name::Component &comp);
+
+ /**
+ * @brief Exclude components from range [from, to]
+ * @param from first element of the range
+ * @param to last element of the range
+ * @returns *this to allow chaining
+ */
+ Exclude &
+ excludeRange (const name::Component &from, const name::Component &to);
+
+ /**
+ * @brief Exclude all components from range [/, to]
+ * @param to last element of the range
+ * @returns *this to allow chaining
+ */
+ inline Exclude &
+ excludeBefore (const name::Component &to);
+
+ /**
+ * @brief Exclude all components from range [from, +Inf]
+ * @param to last element of the range
+ * @returns *this to allow chaining
+ */
+ Exclude &
+ excludeAfter (const name::Component &from);
+
+ /**
+ * @brief Method to directly append exclude element
+ * @param name excluded name component
+ * @param any flag indicating if there is a postfix ANY component after the name
+ *
+ * This method is used during conversion from wire format of exclude filter
+ *
+ * If there is an error with ranges (e.g., order of components is wrong) an exception is thrown
+ */
+ void
+ appendExclude (const name::Component &name, bool any);
+
+ /**
+ * @brief Get number of exclude terms
+ */
+ inline size_t
+ size () const;
+
+ /**
+ * @brief Get begin iterator of the exclude terms
+ */
+ inline const_iterator
+ begin () const;
+
+ /**
+ * @brief Get end iterator of the exclude terms
+ */
+ inline const_iterator
+ end () const;
+
+ /**
+ * @brief Get begin iterator of the exclude terms
+ */
+ inline const_reverse_iterator
+ rbegin () const;
+
+ /**
+ * @brief Get end iterator of the exclude terms
+ */
+ inline const_reverse_iterator
+ rend () const;
+
+private:
+ Exclude &
+ excludeRange (iterator fromLowerBound, iterator toLowerBound);
+
+private:
+ exclude_type m_exclude;
+};
+
+std::ostream&
+operator << (std::ostream &os, const Exclude &name);
+
+inline Exclude &
+Exclude::excludeBefore (const name::Component &to)
+{
+ return excludeRange (name::Component (), to);
+}
+
+inline size_t
+Exclude::size () const
+{
+ return m_exclude.size ();
+}
+
+inline Exclude::const_iterator
+Exclude::begin () const
+{
+ return m_exclude.begin ();
+}
+
+inline Exclude::const_iterator
+Exclude::end () const
+{
+ return m_exclude.end ();
+}
+
+inline Exclude::const_reverse_iterator
+Exclude::rbegin () const
+{
+ return m_exclude.rbegin ();
+}
+
+inline Exclude::const_reverse_iterator
+Exclude::rend () const
+{
+ return m_exclude.rend ();
+}
+
+} // ndn
+
+#endif // NDN_EXCLUDE_H
diff --git a/ndn-cpp/fields/key-locator.cc b/ndn-cpp/fields/key-locator.cc
new file mode 100644
index 0000000..84fd60c
--- /dev/null
+++ b/ndn-cpp/fields/key-locator.cc
@@ -0,0 +1,200 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "key-locator.h"
+#include "ndn-cpp/error.h"
+
+namespace ndn {
+
+KeyLocator::KeyLocator ()
+ : m_type (NOTSET)
+ , m_data (0)
+{
+}
+
+KeyLocator::KeyLocator (const KeyLocator &keyLocator)
+ : m_type (keyLocator.getType ())
+ , m_data (0)
+{
+ switch (m_type)
+ {
+ case NOTSET:
+ break;
+ case KEY:
+ m_data = new Blob (keyLocator.getKey ());
+ break;
+ case CERTIFICATE:
+ m_data = new Blob (keyLocator.getCertificate ());
+ break;
+ case KEYNAME:
+ m_data = new Name (keyLocator.getKeyName ());
+ break;
+ }
+}
+
+KeyLocator::~KeyLocator ()
+{
+ deleteData ();
+}
+
+KeyLocator &
+KeyLocator::operator = (const KeyLocator &keyLocator)
+{
+ if (this == &keyLocator)
+ return *this;
+
+ deleteData ();
+ m_type = keyLocator.getType ();
+
+ switch (m_type)
+ {
+ case NOTSET:
+ break;
+ case KEY:
+ m_data = new Blob (keyLocator.getKey ());
+ break;
+ case CERTIFICATE:
+ m_data = new Blob (keyLocator.getCertificate ());
+ break;
+ case KEYNAME:
+ m_data = new Name (keyLocator.getKeyName ());
+ break;
+ }
+
+ return *this;
+}
+
+void
+KeyLocator::deleteData ()
+{
+ switch (m_type)
+ {
+ case NOTSET: // nothing to clean up
+ break;
+ case KEY:
+ delete reinterpret_cast<Blob*> (m_data);
+ break;
+ case CERTIFICATE:
+ delete reinterpret_cast<Blob*> (m_data);
+ break;
+ case KEYNAME:
+ delete reinterpret_cast<Name*> (m_data);
+ break;
+ }
+}
+
+void
+KeyLocator::setType (KeyLocator::Type type)
+{
+ if (m_type == type)
+ return;
+
+ deleteData ();
+ m_type = type;
+
+ switch (m_type)
+ {
+ case NOTSET:
+ m_data = 0;
+ case KEY:
+ m_data = new Blob;
+ break;
+ case CERTIFICATE:
+ m_data = new Blob;
+ break;
+ case KEYNAME:
+ m_data = new Name;
+ break;
+ }
+}
+
+const Blob &
+KeyLocator::getKey () const
+{
+ if (m_type != KEY)
+ BOOST_THROW_EXCEPTION (error::KeyLocator ()
+ << error::msg ("getKey called, but KeyLocator is not of type KeyLocator::KEY"));
+ return *reinterpret_cast<const Blob*> (m_data);
+}
+
+Blob &
+KeyLocator::getKey ()
+{
+ if (m_type != KEY)
+ BOOST_THROW_EXCEPTION (error::KeyLocator ()
+ << error::msg ("getKey called, but KeyLocator is not of type KeyLocator::KEY"));
+ return *reinterpret_cast<Blob*> (m_data);
+}
+
+void
+KeyLocator::setKey (const Blob &key)
+{
+ if (m_type != KEY)
+ BOOST_THROW_EXCEPTION (error::KeyLocator ()
+ << error::msg ("setKey called, but KeyLocator is not of type KeyLocator::KEY"));
+ *reinterpret_cast<Blob*> (m_data) = key;
+}
+
+const Blob &
+KeyLocator::getCertificate () const
+{
+ if (m_type != CERTIFICATE)
+ BOOST_THROW_EXCEPTION (error::KeyLocator ()
+ << error::msg ("getCertificate called, but KeyLocator is not of type KeyLocator::CERTIFICATE"));
+ return *reinterpret_cast<const Blob*> (m_data);
+}
+
+Blob &
+KeyLocator::getCertificate ()
+{
+ if (m_type != CERTIFICATE)
+ BOOST_THROW_EXCEPTION (error::KeyLocator ()
+ << error::msg ("getCertificate called, but KeyLocator is not of type KeyLocator::CERTIFICATE"));
+ return *reinterpret_cast<Blob*> (m_data);
+}
+
+void
+KeyLocator::setCertificate (const Blob &certificate)
+{
+ if (m_type != CERTIFICATE)
+ BOOST_THROW_EXCEPTION (error::KeyLocator ()
+ << error::msg ("setCertificate called, but KeyLocator is not of type KeyLocator::CERTIFICATE"));
+ *reinterpret_cast<Blob*> (m_data) = certificate;
+}
+
+const Name &
+KeyLocator::getKeyName () const
+{
+ if (m_type != KEYNAME)
+ BOOST_THROW_EXCEPTION (error::KeyLocator ()
+ << error::msg ("getKeyName called, but KeyLocator is not of type KeyLocator::KEYNAME"));
+ return *reinterpret_cast<const Name*> (m_data);
+}
+
+Name &
+KeyLocator::getKeyName ()
+{
+ if (m_type != KEYNAME)
+ BOOST_THROW_EXCEPTION (error::KeyLocator ()
+ << error::msg ("getKeyName called, but KeyLocator is not of type KeyLocator::KEYNAME"));
+ return *reinterpret_cast<Name*> (m_data);
+}
+
+
+void
+KeyLocator::setKeyName (const Name &name)
+{
+ if (m_type != KEYNAME)
+ BOOST_THROW_EXCEPTION (error::KeyLocator ()
+ << error::msg ("setKeyName called, but KeyLocator is not of type KeyLocator::KEYNAME"));
+ *reinterpret_cast<Name*> (m_data) = name;
+}
+
+}
diff --git a/ndn-cpp/fields/key-locator.h b/ndn-cpp/fields/key-locator.h
new file mode 100644
index 0000000..cf1c6ea
--- /dev/null
+++ b/ndn-cpp/fields/key-locator.h
@@ -0,0 +1,168 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_KEY_LOCATOR_H
+#define NDN_KEY_LOCATOR_H
+
+#include "ndn-cpp/fields/blob.h"
+#include "ndn-cpp/fields/name.h"
+
+namespace ndn {
+
+/**
+ * @brief Class providing an interface to work with key locators in NDN data packets
+ */
+class KeyLocator
+{
+public:
+ /**
+ * @brief Key locator type
+ *
+ * Key locator can be only of the defined types, i.e., it cannot contain key bits and key name
+ */
+ enum Type
+ {
+ NOTSET=-1, ///< @brief Unset key locator type, any attempt to use KeyLocator of NOTSET type will cause an exception
+ KEY, ///< @brief Key locator contains key bits
+ CERTIFICATE, ///< @brief Key locator contains certificate bits
+ KEYNAME ///< @brief key locator contains name of the key
+ };
+
+ /**
+ * @brief Default constructor
+ */
+ KeyLocator ();
+
+ /**
+ * @brief Copy constructor
+ */
+ KeyLocator (const KeyLocator &keyLocator);
+
+ /**
+ * @brief Destructor
+ */
+ ~KeyLocator ();
+
+ /**
+ * @brief Copy operator
+ */
+ KeyLocator &
+ operator = (const KeyLocator &keyLocator);
+
+ /**
+ * @brief Set type of the key locator
+ * @param type key locator type, @see Type
+ *
+ * If type of the key locator changes, setType will delete any previously allocated
+ * data, allocate appropriate type and store it in m_data
+ */
+ void
+ setType (Type type);
+
+ /**
+ * @brief Get type of the key locator
+ */
+ inline Type
+ getType () const;
+
+ /**
+ * @brief Get const reference to key bits, associated with key locator
+ *
+ * If key locator type is not KEY, then an exception will be thrown
+ */
+ const Blob &
+ getKey () const;
+
+ /**
+ * @brief Get reference to key bits, associated with key locator
+ *
+ * If key locator type is not KEY, then an exception will be thrown
+ */
+ Blob &
+ getKey ();
+
+ /**
+ * @brief Set key bits, associated with key locator
+ * @param key const reference to key bits
+ *
+ * If key locator type is not KEY, then an exception will be thrown
+ */
+ void
+ setKey (const Blob &key);
+
+ /**
+ * @brief Get const reference to certificated bits, associated with key locator
+ *
+ * If key locator type is not CERTIFICATE, then an exception will be thrown
+ */
+ const Blob &
+ getCertificate () const;
+
+ /**
+ * @brief Get reference to certificated bits, associated with key locator
+ *
+ * If key locator type is not CERTIFICATE, then an exception will be thrown
+ */
+ Blob &
+ getCertificate ();
+
+ /**
+ * @brief Set certificated bits, associated with key locator
+ * @param certificate const reference to certificate bits
+ *
+ * If key locator type is not CERTIFICATE, then an exception will be thrown
+ */
+ void
+ setCertificate (const Blob &certificate);
+
+ /**
+ * @brief Get const reference to key name, associated with key locator
+ *
+ * If key locator type is not KEYNAME, then an exception will be thrown
+ */
+ const Name &
+ getKeyName () const;
+
+ /**
+ * @brief Get reference to key name, associated with key locator
+ *
+ * If key locator type is not KEYNAME, then an exception will be thrown
+ */
+ Name &
+ getKeyName ();
+
+ /**
+ * @brief Set key name, associated with key locator
+ * @param name const reference to key name
+ *
+ * If key locator type is not KEYNAME, then an exception will be thrown
+ */
+ void
+ setKeyName (const Name &name);
+
+private:
+ void
+ deleteData ();
+
+private:
+ Type m_type;
+ void *m_data;
+};
+
+inline KeyLocator::Type
+KeyLocator::getType () const
+{
+ return m_type;
+}
+
+
+} // ndn
+
+#endif // NDN_KEY_LOCATOR_H
diff --git a/ndn-cpp/fields/name-component.cc b/ndn-cpp/fields/name-component.cc
new file mode 100644
index 0000000..ecc87b1
--- /dev/null
+++ b/ndn-cpp/fields/name-component.cc
@@ -0,0 +1,170 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "name-component.h"
+
+#include "ndn-cpp/error.h"
+#include "ndn-cpp/helpers/uri.h"
+
+using namespace std;
+
+namespace ndn
+{
+namespace name
+{
+
+Component::Component ()
+{
+}
+
+Component::Component (const std::string &uri)
+{
+ try
+ {
+ Uri::fromEscaped (uri.begin (), uri.end (), back_inserter (*this));
+ }
+ catch (error::Uri &err)
+ {
+ // re-throwing different exception
+ BOOST_THROW_EXCEPTION (error::name::Component ()
+ << error::msg (uri)
+ << error::pos (error::get_pos (err)));
+ }
+}
+
+Component::Component (std::string::const_iterator begin, std::string::const_iterator end)
+{
+ try
+ {
+ Uri::fromEscaped (begin, end, back_inserter (*this));
+ }
+ catch (error::Uri &err)
+ {
+ // re-throwing different exception
+ BOOST_THROW_EXCEPTION (error::name::Component ()
+ << error::msg (string (begin, end))
+ << error::pos (error::get_pos (err)));
+ }
+}
+
+Component::Component (const void *buf, size_t length)
+{
+ copy (static_cast<const char*> (buf),
+ static_cast<const char*> (buf)+length,
+ back_inserter (*this));
+}
+
+int
+Component::compare (const Component &other) const
+{
+ if (size () < other.size ())
+ return -1;
+
+ if (size () > other.size ())
+ return +1;
+
+ // now we know that sizes are equal
+
+ pair<const_iterator, const_iterator> diff = mismatch (begin (), end (), other.begin ());
+ if (diff.first == end ()) // components are actually equal
+ return 0;
+
+ return (std::lexicographical_compare (diff.first, end (), diff.second, other.end ())) ? -1 : +1;
+}
+
+Component
+Component::fromNumber (uint64_t number)
+{
+ Component comp;
+ while (number > 0)
+ {
+ comp.push_back (static_cast<unsigned char> (number & 0xFF));
+ number >>= 8;
+ }
+ std::reverse (comp.begin (), comp.end ());
+ return comp;
+}
+
+Component
+Component::fromNumberWithMarker (uint64_t number, unsigned char marker)
+{
+ Component comp;
+ comp.push_back (marker);
+
+ while (number > 0)
+ {
+ comp.push_back (static_cast<unsigned char> (number & 0xFF));
+ number >>= 8;
+ }
+
+ std::reverse (comp.begin () + 1, comp.end ());
+ return comp;
+}
+
+std::string
+Component::toBlob () const
+{
+ return std::string (begin (), end ());
+}
+
+void
+Component::toBlob (std::ostream &os) const
+{
+ os.write (buf (), size ());
+}
+
+std::string
+Component::toUri () const
+{
+ ostringstream os;
+ toUri (os);
+ return os.str ();
+}
+
+void
+Component::toUri (std::ostream &os) const
+{
+ Uri::toEscaped (begin (), end (), ostream_iterator<char> (os));
+}
+
+uint64_t
+Component::toNumber () const
+{
+ uint64_t ret = 0;
+ for (const_iterator i = begin (); i != end (); i++)
+ {
+ ret <<= 8;
+ ret |= static_cast<unsigned char> (*i);
+ }
+ return ret;
+}
+
+uint64_t
+Component::toNumberWithMarker (unsigned char marker) const
+{
+ if (empty () ||
+ static_cast<unsigned char> (*(begin ())) != marker)
+ {
+ BOOST_THROW_EXCEPTION (error::name::Component ()
+ << error::msg ("Name component does not have required marker [" + toUri () + "]"));
+ }
+
+ uint64_t ret = 0;
+ for (const_iterator i = begin () + 1; i != end (); i++)
+ {
+ ret <<= 8;
+ ret |= static_cast<unsigned char> (*i);
+ }
+ return ret;
+}
+
+
+} // name
+} // ndn
diff --git a/ndn-cpp/fields/name-component.h b/ndn-cpp/fields/name-component.h
new file mode 100644
index 0000000..0bcf862
--- /dev/null
+++ b/ndn-cpp/fields/name-component.h
@@ -0,0 +1,282 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_NAME_COMPONENT_H
+#define NDN_NAME_COMPONENT_H
+
+#include <string>
+#include <vector>
+
+#include "blob.h"
+#include <stdint.h>
+
+namespace ndn {
+
+namespace name {
+
+/**
+ * @brief Class to representing binary blob of NDN name component
+ *
+ * This class is based on std::vector<char> and just provides several helpers
+ * to work with name components, as well as operator to apply canonical
+ * ordering on name components
+ */
+class Component : public Blob
+{
+public:
+ /**
+ * @brief Default constructor an empty exclude
+ */
+ Component ();
+
+ /**
+ * @brief Create component from URI encoded string
+ * @param uri URI encoded name component (convert escaped with % characters)
+ */
+ Component (const std::string &uri);
+
+ /**
+ * @brief Create component from URI encoded string, with string specified by a pair of iterators
+ * @param begin begin iterator pointing to the URI encoded name
+ * @param end end iterator
+ */
+ Component (std::string::const_iterator begin, std::string::const_iterator end);
+
+ /**
+ * @brief Create component using a binary blob
+ * @param buf pointer to first byte of binary blob to store as a name component
+ * @param length length of the binary blob
+ */
+ Component (const void *buf, size_t length);
+
+ /**
+ * @brief Apply canonical ordering on component comparison
+ * @return 0 They compare equal
+ * <0 If *this comes before other in the canonical ordering
+ * >0 If *this comes after in the canonical ordering
+ *
+ * @see http://www.ccnx.org/releases/latest/doc/technical/CanonicalOrder.html
+ */
+ int
+ compare (const Component &other) const;
+
+ /**
+ * @brief Apply canonical ordering on component comparison (less or equal)
+ *
+ * @see http://www.ccnx.org/releases/latest/doc/technical/CanonicalOrder.html
+ */
+ inline bool
+ operator <= (const Component &other) const;
+
+ /**
+ * @brief Apply canonical ordering on component comparison (less)
+ *
+ * @see http://www.ccnx.org/releases/latest/doc/technical/CanonicalOrder.html
+ */
+ inline bool
+ operator < (const Component &other) const;
+
+ /**
+ * @brief Apply canonical ordering on component comparison (greater or equal)
+ *
+ * @see http://www.ccnx.org/releases/latest/doc/technical/CanonicalOrder.html
+ */
+ inline bool
+ operator >= (const Component &other) const;
+
+ /**
+ * @brief Apply canonical ordering on component comparison (greater)
+ *
+ * @see http://www.ccnx.org/releases/latest/doc/technical/CanonicalOrder.html
+ */
+ inline bool
+ operator > (const Component &other) const;
+
+ ////////////////////////////////////
+ // Component construction helpers //
+ ////////////////////////////////////
+
+ /**
+ * @brief Create network-ordered numeric component
+ *
+ * @param number number to be encoded and added as a component
+ *
+ * Number is encoded and added in network order. Tail zero-bytes are not included.
+ * For example, if the number is 1, then 1-byte binary blob will be added 0x01.
+ * If the number is 256, then 2 binary blob will be added: 0x01 0x01
+ *
+ * If the number is zero, an empty component will be created
+ */
+ static Component
+ fromNumber (uint64_t number);
+
+ /**
+ * @brief Create network-ordered numeric component to the name with marker
+ *
+ * @param number number to be encoded and added as a component
+ * @param marker byte marker, specified by the desired naming convention
+ *
+ * Currently defined naming conventions of the marker:
+ * - 0x00 sequence number
+ * - 0xC1 control number
+ * - 0xFB block id
+ * - 0xFD version number
+ *
+ * This version is almost exactly as appendNumber, with exception that it adds initial marker.
+ * The number is formatted in the exactly the same way.
+ *
+ * @see fromNumber
+ */
+ static Component
+ fromNumberWithMarker (uint64_t number, unsigned char marker);
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // helpers
+ //////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * @brief Convert binary blob name component to std::string (no conversion is made)
+ * @param comp name component to be converted
+ * @see asUriString
+ */
+ std::string
+ toBlob () const;
+
+ /**
+ * @brief Write blob of the name component to the specified output stream
+ * @param os output stream
+ */
+ void
+ toBlob (std::ostream &os) const;
+
+ /**
+ * @brief Convert binary blob name component to std::string, escaping all non-printable characters in URI format
+ * @param comp name component to be converted
+ * @see asString
+ */
+ std::string
+ toUri () const;
+
+ /**
+ * @brief Write name as URI to the specified output stream
+ * @param os output stream
+ */
+ void
+ toUri (std::ostream &os) const;
+
+ /**
+ * @brief Convert binary blob name component (network-ordered number) to number
+ * @param comp name component to be converted
+ */
+ uint64_t
+ toNumber () const;
+
+ /**
+ * @brief Convert binary blob name component (network-ordered number) to number, using appropriate marker from the naming convention
+ * @param comp name component to be converted
+ * @param marker required marker from the naming convention
+ *
+ * If the required marker does not exist, an exception will be thrown
+ */
+ uint64_t
+ toNumberWithMarker (unsigned char marker) const;
+
+ /**
+ * @brief Convert binary blob name component, assuming sequence number naming convention (marker = 0x00)
+ * @param comp name component to be converted
+ * @see asNumberWithMarker
+ */
+ inline uint64_t
+ toSeqNum () const;
+
+ /**
+ * @brief Convert binary blob name component, assuming control number naming convention (marker = 0xC1)
+ * @param comp name component to be converted
+ * @see asNumberWithMarker
+ */
+ inline uint64_t
+ toControlNum () const;
+
+ /**
+ * @brief Convert binary blob name component, assuming block ID naming convention (marker = 0xFB)
+ * @param comp name component to be converted
+ * @see asNumberWithMarker
+ */
+ inline uint64_t
+ toBlkId () const;
+
+ /**
+ * @brief Convert binary blob name component, assuming time-stamping version naming convention (marker = 0xFD)
+ * @param comp name component to be converted
+ * @see asNumberWithMarker
+ */
+ inline uint64_t
+ toVersion () const;
+};
+
+bool
+Component::operator <= (const Component &other) const
+{
+ return (compare (other) <= 0);
+}
+
+bool
+Component::operator < (const Component &other) const
+{
+ return (compare (other) < 0);
+}
+
+bool
+Component::operator >= (const Component &other) const
+{
+ return (compare (other) >= 0);
+}
+
+bool
+Component::operator > (const Component &other) const
+{
+ return (compare (other) > 0);
+}
+
+inline uint64_t
+Component::toSeqNum () const
+{
+ return toNumberWithMarker (0x00);
+}
+
+inline uint64_t
+Component::toControlNum () const
+{
+ return toNumberWithMarker (0xC1);
+}
+
+inline uint64_t
+Component::toBlkId () const
+{
+ return toNumberWithMarker (0xFB);
+}
+
+inline uint64_t
+Component::toVersion () const
+{
+ return toNumberWithMarker (0xFD);
+}
+
+/**
+ * @brief Stream output operator (output in escaped URI format)
+ */
+std::ostream&
+operator <<(std::ostream &os, const Component &name);
+
+} // name
+
+} // ndn
+
+#endif // NDN_EXCLUDE_H
diff --git a/ndn-cpp/fields/name.cc b/ndn-cpp/fields/name.cc
new file mode 100644
index 0000000..d3e2ec6
--- /dev/null
+++ b/ndn-cpp/fields/name.cc
@@ -0,0 +1,264 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ * Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#include "name.h"
+
+#include "ndn-cpp/error.h"
+#include <boost/algorithm/string.hpp>
+
+#include <ctype.h>
+
+using namespace std;
+
+namespace ndn
+{
+
+///////////////////////////////////////////////////////////////////////////////
+// CONSTRUCTORS //
+///////////////////////////////////////////////////////////////////////////////
+
+Name::Name ()
+{
+}
+
+Name::Name (const string &uri)
+{
+ string::const_iterator i = uri.begin ();
+ string::const_iterator end = uri.end ();
+
+ string::const_iterator firstSlash = std::find (i, end, '/');
+ if (firstSlash == end)
+ {
+ BOOST_THROW_EXCEPTION (error::Name ()
+ << error::msg ("Name should include at least one slash (did you forget to specify initial /?)"));
+ }
+
+ if (firstSlash != i)
+ {
+ string schema (i, firstSlash);
+ if (*schema.rbegin () != ':')
+ {
+ BOOST_THROW_EXCEPTION (error::Name ()
+ << error::msg ("First component of the name does not start with a slash (did you forget to specify initial /?)"));
+ }
+
+ i = firstSlash;
+
+ if (!boost::iequals (schema, "ccnx:") &&
+ !boost::iequals (schema, "ndn:"))
+ {
+ BOOST_THROW_EXCEPTION (error::Name ()
+ << error::msg ("URI schema is not supported (only ccnx: or ndn: is allowed)")
+ << error::msg (schema));
+ }
+ }
+
+ string::const_iterator secondSlash = i;
+ secondSlash ++;
+ if (secondSlash != end && *secondSlash == '/')
+ {
+ // The authority component (the part after the initial "//" in the familiar http and ftp URI schemes) is present,
+ // but it is not relevant to NDN name.
+ // skipping it
+ secondSlash ++;
+ i = std::find (secondSlash, end, '/');
+ }
+
+ if (i == end)
+ {
+ BOOST_THROW_EXCEPTION (error::Name ()
+ << error::msg ("Invalid URI")
+ << error::msg (uri));
+ }
+
+ while (i != end)
+ {
+ // skip any extra slashes
+ while (i != end && *i == '/')
+ {
+ i ++;
+ }
+ if (i == end)
+ break;
+
+ string::const_iterator endOfComponent = std::find (i, end, '/');
+ append (name::Component (i, endOfComponent));
+
+ i = endOfComponent;
+ }
+}
+
+Name::Name (const Name &other)
+{
+ m_comps = other.m_comps;
+}
+
+Name &
+Name::operator= (const Name &other)
+{
+ m_comps = other.m_comps;
+ return *this;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// SETTERS //
+///////////////////////////////////////////////////////////////////////////////
+
+Name &
+Name::appendVersion (uint64_t version/* = Name::nversion*/)
+{
+ if (version != Name::nversion)
+ return appendNumberWithMarker (version, 0xFD);
+ else
+ {
+ TimeInterval now = time::NowUnixTimestamp ();
+ version = (now.total_seconds () << 12) | (0xFFF & (now.fractional_seconds () / 244 /*( 1000,000 microseconds / 4096.0 resolution = last 12 bits)*/));
+ return appendNumberWithMarker (version, 0xFD);
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// GETTERS //
+///////////////////////////////////////////////////////////////////////////////
+
+const name::Component &
+Name::get (int index) const
+{
+ if (index < 0)
+ {
+ index = size () - (-index);
+ }
+
+ if (static_cast<unsigned int> (index) >= size ())
+ {
+ BOOST_THROW_EXCEPTION (error::Name ()
+ << error::msg ("Index out of range")
+ << error::pos (index));
+ }
+ return m_comps [index];
+}
+
+name::Component &
+Name::get (int index)
+{
+ if (index < 0)
+ {
+ index = size () - (-index);
+ }
+
+ if (static_cast<unsigned int> (index) >= size())
+ {
+ BOOST_THROW_EXCEPTION (error::Name ()
+ << error::msg ("Index out of range")
+ << error::pos (index));
+ }
+ return m_comps [index];
+}
+
+
+/////
+///// Static helpers to convert name component to appropriate value
+/////
+
+
+Name
+Name::getSubName (size_t pos/* = 0*/, size_t len/* = Name::npos*/) const
+{
+ Name retval;
+
+ if (len == npos)
+ {
+ len = size () - pos;
+ }
+
+ if (pos + len > size ())
+ {
+ BOOST_THROW_EXCEPTION (error::Name ()
+ << error::msg ("getSubName parameter out of range")
+ << error::pos (pos)
+ << error::pos (len));
+ }
+
+ for (size_t i = pos; i < pos + len; i++)
+ {
+ retval.append (get (i));
+ }
+
+ return retval;
+}
+
+Name
+Name::operator+ (const Name &name) const
+{
+ Name newName;
+ newName
+ .append (*this)
+ .append (name);
+
+ return newName;
+}
+
+std::string
+Name::toUri () const
+{
+ ostringstream os;
+ toUri (os);
+ return os.str ();
+}
+
+void
+Name::toUri (std::ostream &os) const
+{
+ for (Name::const_iterator comp = begin (); comp != end (); comp++)
+ {
+ os << "/";
+ comp->toUri (os);
+ }
+ if (size () == 0)
+ os << "/";
+}
+
+// ostream &
+// operator << (ostream &os, const Name &name)
+// {
+// for (Name::const_iterator comp = name.begin (); comp != name.end (); comp++)
+// {
+// os << "/" << *comp;
+// }
+// if (name.size () == 0)
+// os << "/";
+// return os;
+// }
+
+int
+Name::compare (const Name &name) const
+{
+ Name::const_iterator i = this->begin ();
+ Name::const_iterator j = name.begin ();
+
+ for (; i != this->end () && j != name.end (); i++, j++)
+ {
+ int res = i->compare (*j);
+ if (res == 0)
+ continue;
+ else
+ return res;
+ }
+
+ if (i == this->end () && j == name.end ())
+ return 0; // prefixes are equal
+
+ return (i == this->end ()) ? -1 : +1;
+}
+
+} // ndn
diff --git a/ndn-cpp/fields/name.h b/ndn-cpp/fields/name.h
new file mode 100644
index 0000000..18e2412
--- /dev/null
+++ b/ndn-cpp/fields/name.h
@@ -0,0 +1,637 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ * Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#ifndef NDN_NAME_H
+#define NDN_NAME_H
+
+#include "ndn-cpp/fields/name-component.h"
+#include "ndn-cpp/common.h"
+
+namespace ndn {
+
+/**
+ * @brief Class for NDN Name
+ */
+class Name
+{
+public:
+ typedef std::vector<name::Component>::iterator iterator;
+ typedef std::vector<name::Component>::const_iterator const_iterator;
+ typedef std::vector<name::Component>::reverse_iterator reverse_iterator;
+ typedef std::vector<name::Component>::const_reverse_iterator const_reverse_iterator;
+ typedef std::vector<name::Component>::reference reference;
+ typedef std::vector<name::Component>::const_reference const_reference;
+
+ typedef name::Component partial_type;
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // CONSTRUCTORS //
+ ///////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * @brief Default constructor to create an empty name (zero components, or "/")
+ */
+ Name ();
+
+ /**
+ * @brief Copy constructor
+ *
+ * @param other reference to a NDN name object
+ */
+ Name (const Name &other);
+
+ /**
+ * @brief Create a name from URL string
+ *
+ * @param url URI-represented name
+ */
+ Name (const std::string &url);
+
+ /**
+ * @brief Create a name from a container of elements [begin, end)
+ *
+ * @param begin begin iterator of the container
+ * @param end end iterator of the container
+ */
+ template<class Iterator>
+ Name (Iterator begin, Iterator end);
+
+ /**
+ * @brief Assignment operator
+ */
+ Name &
+ operator= (const Name &other);
+
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // SETTERS //
+ ///////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * @brief Append a binary blob as a name component
+ *
+ * @param comp a binary blob
+ * @returns reference to self (to allow chaining of append methods)
+ */
+ inline Name &
+ append (const name::Component &comp);
+
+ /**
+ * @brief Append a binary blob as a name component
+ * @param comp a binary blob
+ *
+ * This version is a little bit more efficient, since it swaps contents of comp and newly added component
+ *
+ * Attention!!! This method has an intended side effect: content of comp becomes empty
+ */
+ inline Name &
+ appendBySwap (name::Component &comp);
+
+ /**
+ * @brief Append components a container of elements [begin, end)
+ *
+ * @param begin begin iterator of the container
+ * @param end end iterator of the container
+ * @returns reference to self (to allow chaining of append methods)
+ */
+ template<class Iterator>
+ inline Name &
+ append (Iterator begin, Iterator end);
+
+ /**
+ * @brief Append components from another ndn::Name object
+ *
+ * @param comp reference to Name object
+ * @returns reference to self (to allow chaining of append methods)
+ */
+ inline Name &
+ append (const Name &comp);
+
+ /**
+ * @brief Append a string as a name component
+ *
+ * @param compStr a string
+ * @returns reference to self (to allow chaining of append methods)
+ *
+ * No conversions will be done to the string. The string is included in raw form,
+ * without any leading '\0' symbols.
+ */
+ inline Name &
+ append (const std::string &compStr);
+
+ /**
+ * @brief Append a binary blob as a name component
+ *
+ * @param buf pointer to the first byte of the binary blob
+ * @param size length of the binary blob
+ * @returns reference to self (to allow chaining of append methods)
+ */
+ inline Name &
+ append (const void *buf, size_t size);
+
+ /**
+ * @brief Append network-ordered numeric component to the name
+ *
+ * @param number number to be encoded and added as a component
+ *
+ * Number is encoded and added in network order. Tail zero-bytes are not included.
+ * For example, if the number is 1, then 1-byte binary blob will be added 0x01.
+ * If the number is 256, then 2 binary blob will be added: 0x01 0x01
+ *
+ * If the number is zero, an empty component will be added
+ */
+ inline Name &
+ appendNumber (uint64_t number);
+
+ /**
+ * @brief Append network-ordered numeric component to the name with marker
+ *
+ * @param number number to be encoded and added as a component
+ * @param marker byte marker, specified by the desired naming convention
+ *
+ * Currently defined naming conventions of the marker:
+ * - 0x00 sequence number
+ * - 0xC1 control number
+ * - 0xFB block id
+ * - 0xFD version number
+ *
+ * This version is almost exactly as appendNumber, with exception that it adds initial marker.
+ * The number is formatted in the exactly the same way.
+ *
+ * @see appendNumber
+ */
+ inline Name &
+ appendNumberWithMarker (uint64_t number, unsigned char marker);
+
+ /**
+ * @brief Helper method to add sequence number to the name (marker = 0x00)
+ * @param seqno sequence number
+ * @see appendNumberWithMarker
+ */
+ inline Name &
+ appendSeqNum (uint64_t seqno);
+
+ /**
+ * @brief Helper method to add control number to the name (marker = 0xC1)
+ * @param control control number
+ * @see appendNumberWithMarker
+ */
+ inline Name &
+ appendControlNum (uint64_t control);
+
+ /**
+ * @brief Helper method to add block ID to the name (marker = 0xFB)
+ * @param blkid block ID
+ * @see appendNumberWithMarker
+ */
+ inline Name &
+ appendBlkId (uint64_t blkid);
+
+ /**
+ * @brief Helper method to add version to the name (marker = 0xFD)
+ * @param version fully formatted version in a desired format (e.g., timestamp).
+ * If version is Name::nversion, then the version number is automatically
+ * assigned based on UTC timestamp
+ * @see appendNumberWithMarker
+ */
+ Name &
+ appendVersion (uint64_t version = Name::nversion);
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // GETTERS //
+ ///////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * @brief Get number of the name components
+ * @return number of name components
+ */
+ inline size_t
+ size () const;
+
+ /**
+ * @brief Get binary blob of name component
+ * @param index index of the name component. If less than 0, then getting component from the back:
+ * get(-1) getting the last component, get(-2) is getting second component from back, etc.
+ * @returns const reference to binary blob of the requested name component
+ *
+ * If index is out of range, an exception will be thrown
+ */
+ const name::Component &
+ get (int index) const;
+
+ /**
+ * @brief Get binary blob of name component
+ * @param index index of the name component. If less than 0, then getting component from the back
+ * @returns reference to binary blob of the requested name component
+ *
+ * If index is out of range, an exception will be thrown
+ */
+ name::Component &
+ get (int index);
+
+ /////
+ ///// Iterator interface to name components
+ /////
+ inline Name::const_iterator
+ begin () const; ///< @brief Begin iterator (const)
+
+ inline Name::iterator
+ begin (); ///< @brief Begin iterator
+
+ inline Name::const_iterator
+ end () const; ///< @brief End iterator (const)
+
+ inline Name::iterator
+ end (); ///< @brief End iterator
+
+ inline Name::const_reverse_iterator
+ rbegin () const; ///< @brief Reverse begin iterator (const)
+
+ inline Name::reverse_iterator
+ rbegin (); ///< @brief Reverse begin iterator
+
+ inline Name::const_reverse_iterator
+ rend () const; ///< @brief Reverse end iterator (const)
+
+ inline Name::reverse_iterator
+ rend (); ///< @brief Reverse end iterator
+
+
+ /////
+ ///// Static helpers to convert name component to appropriate value
+ /////
+
+ /**
+ * @brief Get a new name, constructed as a subset of components
+ * @param pos Position of the first component to be copied to the subname
+ * @param len Number of components to be copied. Value Name::npos indicates that all components till the end of the name.
+ */
+ Name
+ getSubName (size_t pos = 0, size_t len = npos) const;
+
+ /**
+ * @brief Get prefix of the name
+ * @param len length of the prefix
+ * @param skip number of components to skip from beginning of the name
+ */
+ inline Name
+ getPrefix (size_t len, size_t skip = 0) const;
+
+ /**
+ * @brief Get postfix of the name
+ * @param len length of the postfix
+ * @param skip number of components to skip from end of the name
+ */
+ inline Name
+ getPostfix (size_t len, size_t skip = 0) const;
+
+ /**
+ * @brief Get text representation of the name (URI)
+ */
+ std::string
+ toUri () const;
+
+ /**
+ * @brief Write name as URI to the specified output stream
+ * @param os output stream
+ */
+ void
+ toUri (std::ostream &os) const;
+
+ /////////////////////////////////////////////////
+ // Helpers and compatibility wrappers
+ /////////////////////////////////////////////////
+
+ /**
+ * @brief Compare two names, using canonical ordering for each component
+ * @return 0 They compare equal
+ * <0 If *this comes before other in the canonical ordering
+ * >0 If *this comes after in the canonical ordering
+ */
+ int
+ compare (const Name &name) const;
+
+ /**
+ * @brief Check if to Name objects are equal (have the same number of components with the same binary data)
+ */
+ inline bool
+ operator == (const Name &name) const;
+
+ /**
+ * @brief Check if two Name objects are not equal
+ */
+ inline bool
+ operator != (const Name &name) const;
+
+ /**
+ * @brief Less or equal comparison of two name objects
+ */
+ inline bool
+ operator <= (const Name &name) const;
+
+ /**
+ * @brief Less comparison of two name objects
+ */
+ inline bool
+ operator < (const Name &name) const;
+
+ /**
+ * @brief Great or equal comparison of two name objects
+ */
+ inline bool
+ operator >= (const Name &name) const;
+
+ /**
+ * @brief Great comparison of two name objects
+ */
+ inline bool
+ operator > (const Name &name) const;
+
+ /**
+ * @brief Operator [] to simplify access to name components
+ * @see get
+ */
+ inline name::Component &
+ operator [] (int index);
+
+ /**
+ * @brief Operator [] to simplify access to name components
+ * @see get
+ */
+ inline const name::Component &
+ operator [] (int index) const;
+
+ /**
+ * @brief Create a new Name object, by copying components from first and second name
+ */
+ Name
+ operator + (const Name &name) const;
+
+ /**
+ * @brief A wrapper for append method
+ */
+ template<class T>
+ inline void
+ push_back (const T &comp);
+
+public:
+ // Data Members (public):
+ /// Value returned by various member functions when they fail.
+ const static size_t npos = static_cast<size_t> (-1);
+ const static uint64_t nversion = static_cast<uint64_t> (-1);
+
+private:
+ std::vector<name::Component> m_comps;
+};
+
+typedef boost::shared_ptr<Name> NamePtr;
+
+inline std::ostream &
+operator << (std::ostream &os, const Name &name)
+{
+ name.toUri (os);
+ return os;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Definition of inline methods
+/////////////////////////////////////////////////////////////////////////////////////
+
+template<class Iterator>
+Name::Name (Iterator begin, Iterator end)
+{
+ append (begin, end);
+}
+
+inline Name &
+Name::append (const name::Component &comp)
+{
+ if (comp.size () != 0)
+ m_comps.push_back (comp);
+ return *this;
+}
+
+inline Name &
+Name::appendBySwap (name::Component &comp)
+{
+ if (comp.size () != 0)
+ {
+ Name::iterator newComp = m_comps.insert (end (), name::Component ());
+ newComp->swap (comp);
+ }
+ return *this;
+}
+
+template<class Iterator>
+inline Name &
+Name::append (Iterator begin, Iterator end)
+{
+ for (Iterator i = begin; i != end; i++)
+ {
+ append (*i);
+ }
+ return *this;
+}
+
+Name &
+Name::append (const Name &comp)
+{
+ if (this == &comp)
+ {
+ // have to double-copy if the object is self, otherwise results very frustrating (because we use vector...)
+ return append (Name (comp.begin (), comp.end ()));
+ }
+ return append (comp.begin (), comp.end ());
+}
+
+Name &
+Name::append (const std::string &compStr)
+{
+ name::Component comp (compStr);
+ return appendBySwap (comp);
+}
+
+Name &
+Name::append (const void *buf, size_t size)
+{
+ name::Component comp (buf, size);
+ return appendBySwap (comp);
+}
+
+Name &
+Name::appendNumber (uint64_t number)
+{
+ name::Component comp;
+ name::Component::fromNumber (number).swap (comp);
+ return appendBySwap (comp);
+}
+
+Name &
+Name::appendNumberWithMarker (uint64_t number, unsigned char marker)
+{
+ name::Component comp;
+ name::Component::fromNumberWithMarker (number, marker).swap (comp);
+ return appendBySwap (comp);
+}
+
+inline Name &
+Name::appendSeqNum (uint64_t seqno)
+{
+ return appendNumberWithMarker (seqno, 0x00);
+}
+
+inline Name &
+Name::appendControlNum (uint64_t control)
+{
+ return appendNumberWithMarker (control, 0xC1);
+}
+
+inline Name &
+Name::appendBlkId (uint64_t blkid)
+{
+ return appendNumberWithMarker (blkid, 0xFB);
+}
+
+inline size_t
+Name::size () const
+{
+ return m_comps.size ();
+}
+
+/////
+///// Iterator interface to name components
+/////
+inline Name::const_iterator
+Name::begin () const
+{
+ return m_comps.begin ();
+}
+
+inline Name::iterator
+Name::begin ()
+{
+ return m_comps.begin ();
+}
+
+inline Name::const_iterator
+Name::end () const
+{
+ return m_comps.end ();
+}
+
+inline Name::iterator
+Name::end ()
+{
+ return m_comps.end ();
+}
+
+inline Name::const_reverse_iterator
+Name::rbegin () const
+{
+ return m_comps.rbegin ();
+}
+
+inline Name::reverse_iterator
+Name::rbegin ()
+{
+ return m_comps.rbegin ();
+}
+
+inline Name::const_reverse_iterator
+Name::rend () const
+{
+ return m_comps.rend ();
+}
+
+
+inline Name::reverse_iterator
+Name::rend ()
+{
+ return m_comps.rend ();
+}
+
+
+//// helpers
+
+
+inline Name
+Name::getPrefix (size_t len, size_t skip/* = 0*/) const
+{
+ return getSubName (skip, len);
+}
+
+inline Name
+Name::getPostfix (size_t len, size_t skip/* = 0*/) const
+{
+ return getSubName (size () - len - skip, len);
+}
+
+
+template<class T>
+inline void
+Name::push_back (const T &comp)
+{
+ append (comp);
+}
+
+inline bool
+Name::operator ==(const Name &name) const
+{
+ return (compare (name) == 0);
+}
+
+inline bool
+Name::operator !=(const Name &name) const
+{
+ return (compare (name) != 0);
+}
+
+inline bool
+Name::operator <= (const Name &name) const
+{
+ return (compare (name) <= 0);
+}
+
+inline bool
+Name::operator < (const Name &name) const
+{
+ return (compare (name) < 0);
+}
+
+inline bool
+Name::operator >= (const Name &name) const
+{
+ return (compare (name) >= 0);
+}
+
+inline bool
+Name::operator > (const Name &name) const
+{
+ return (compare (name) > 0);
+}
+
+inline name::Component &
+Name::operator [] (int index)
+{
+ return get (index);
+}
+
+inline const name::Component &
+Name::operator [] (int index) const
+{
+ return get (index);
+}
+
+} // ndn
+
+#endif
diff --git a/ndn-cpp/fields/signature-sha256-with-rsa.cc b/ndn-cpp/fields/signature-sha256-with-rsa.cc
new file mode 100644
index 0000000..c84ef5a
--- /dev/null
+++ b/ndn-cpp/fields/signature-sha256-with-rsa.cc
@@ -0,0 +1,30 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "signature-sha256-with-rsa.h"
+#include "ndn-cpp/wire/base.h"
+
+namespace ndn {
+namespace signature {
+
+const std::string Sha256WithRsa::s_oid = "2.16.840.1.101.3.4.2.1";
+
+Sha256WithRsa::~Sha256WithRsa ()
+{
+}
+
+void
+Sha256WithRsa::doubleDispatch (std::ostream &os, wire::Base &wire, void *userData) const
+{
+ wire.appendSignature (os, *this, userData);
+}
+
+} // signature
+} // ndn
diff --git a/ndn-cpp/fields/signature-sha256-with-rsa.h b/ndn-cpp/fields/signature-sha256-with-rsa.h
new file mode 100644
index 0000000..be6766b
--- /dev/null
+++ b/ndn-cpp/fields/signature-sha256-with-rsa.h
@@ -0,0 +1,172 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_SIGNATURE_SHA256_WITH_RSA_H
+#define NDN_SIGNATURE_SHA256_WITH_RSA_H
+
+#include "signature.h"
+
+#include "ndn-cpp/fields/blob.h"
+#include "ndn-cpp/fields/key-locator.h"
+
+#include <string>
+
+namespace ndn {
+
+namespace signature {
+
+/**
+ * @brief Class providing operations to work with SHA256withRSA (OID: "2.16.840.1.101.3.4.2.1")
+ */
+class Sha256WithRsa : public virtual Signature
+{
+public:
+ /**
+ * @brief Virtual destructor
+ */
+ virtual
+ ~Sha256WithRsa ();
+
+ /**
+ * @brief Get OID of the signature algorithm
+ */
+ inline const std::string &
+ getDigestAlgorithm () const;
+
+ /**
+ * @brief Get reference to signature bits
+ */
+ inline Blob &
+ getSignatureBits ();
+
+ /**
+ * @brief Get const reference to signature bits
+ */
+ inline const Blob &
+ getSignatureBits () const;
+
+ /**
+ * @brief Set signature bits
+ */
+ inline void
+ setSignatureBits (const Blob &signatureBits);
+
+ /**
+ * @brief Get reference to publisher key digest bits
+ */
+ inline Blob &
+ getPublisherKeyDigest ();
+
+ /**
+ * @brief Get const reference to publisher key digest bits
+ */
+ inline const Blob &
+ getPublisherKeyDigest () const;
+
+ /**
+ * @brief Set publisher key digest bits
+ */
+ inline void
+ setPublisherKeyDigest (const Blob &publisherKeyDigest);
+
+ /**
+ * @brief Get reference to key locator object
+ */
+ inline KeyLocator &
+ getKeyLocator ();
+
+ /**
+ * @brief Get const reference to key locator object
+ */
+ inline const KeyLocator &
+ getKeyLocator () const;
+
+ /**
+ * @brief Set key locator object
+ */
+ inline void
+ setKeyLocator (const KeyLocator &keyLocator);
+
+ // from Signature
+ virtual void
+ doubleDispatch (std::ostream &os, wire::Base &wire, void *userData) const;
+
+private:
+ static const std::string s_oid;
+
+ Blob m_signatureBits;
+ Blob m_publisherKeyDigest;
+ KeyLocator m_keyLocator;
+};
+
+const std::string &
+Sha256WithRsa::getDigestAlgorithm () const
+{
+ return s_oid;
+}
+
+inline Blob &
+Sha256WithRsa::getSignatureBits ()
+{
+ return m_signatureBits;
+}
+
+inline const Blob &
+Sha256WithRsa::getSignatureBits () const
+{
+ return m_signatureBits;
+}
+
+inline void
+Sha256WithRsa::setSignatureBits (const Blob &signatureBits)
+{
+ m_signatureBits = signatureBits;
+}
+
+inline Blob &
+Sha256WithRsa::getPublisherKeyDigest ()
+{
+ return m_publisherKeyDigest;
+}
+
+inline const Blob &
+Sha256WithRsa::getPublisherKeyDigest () const
+{
+ return m_publisherKeyDigest;
+}
+
+inline void
+Sha256WithRsa::setPublisherKeyDigest (const Blob &publisherKeyDigest)
+{
+ m_publisherKeyDigest = publisherKeyDigest;
+}
+
+inline KeyLocator &
+Sha256WithRsa::getKeyLocator ()
+{
+ return m_keyLocator;
+}
+
+inline const KeyLocator &
+Sha256WithRsa::getKeyLocator () const
+{
+ return m_keyLocator;
+}
+
+inline void
+Sha256WithRsa::setKeyLocator (const KeyLocator &keyLocator)
+{
+ m_keyLocator = keyLocator;
+}
+
+} // signature
+} // ndn
+
+#endif // NDN_EXCLUDE_H
diff --git a/ndn-cpp/fields/signature.cc b/ndn-cpp/fields/signature.cc
new file mode 100644
index 0000000..4c7a3a5
--- /dev/null
+++ b/ndn-cpp/fields/signature.cc
@@ -0,0 +1,18 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "signature.h"
+#include "ndn-cpp/error.h"
+
+namespace ndn
+{
+
+
+} // ndn
diff --git a/ndn-cpp/fields/signature.h b/ndn-cpp/fields/signature.h
new file mode 100644
index 0000000..a9fb39a
--- /dev/null
+++ b/ndn-cpp/fields/signature.h
@@ -0,0 +1,44 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_SIGNATURE_H
+#define NDN_SIGNATURE_H
+
+#include <iostream>
+
+namespace ndn {
+
+namespace wire { class Base; }
+
+/**
+ * @brief Pure virtual class providing an interface to work with signatures for NDN data packets
+ */
+class Signature
+{
+public:
+ /**
+ * @brief Virtual destructor
+ */
+ virtual
+ ~Signature () { }
+
+ /**
+ * @brief A double dispatch pattern to call the right wireFormatter method to format signature
+ * @param os reference to output stream
+ * @param wireFormatter a reference to a wireFormatter object
+ * @param userData any user-specific data
+ */
+ virtual void
+ doubleDispatch (std::ostream &os, wire::Base &wireFormatter, void *userData) const = 0;
+};
+
+} // ndn
+
+#endif // NDN_SIGNATURE_H
diff --git a/ndn-cpp/fields/signed-blob.h b/ndn-cpp/fields/signed-blob.h
new file mode 100644
index 0000000..2686977
--- /dev/null
+++ b/ndn-cpp/fields/signed-blob.h
@@ -0,0 +1,98 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_SIGNED_BLOB_H
+#define NDN_SIGNED_BLOB_H
+
+#include "blob.h"
+
+namespace ndn {
+
+/**
+ * @brief Class representing a blob, which has a signed portion (e.g., bytes of DATA packet)
+ */
+class SignedBlob : public Blob
+{
+public:
+ /**
+ * @brief Set signed portion of the blob
+ * @param offset An offset from the beginning of the blob
+ * @param size Size of the signed portion of the blob
+ */
+ inline void
+ setSignedPortion (size_t offset, size_t size);
+
+ /**
+ * @brief Get begin iterator to a signed portion of the blob
+ */
+ inline const_iterator
+ signed_begin () const;
+
+ /**
+ * @brief Get end iterator of a signed portion of the blob
+ */
+ inline const_iterator
+ signed_end () const;
+
+ /**
+ * @brief Get pointer to a first byte of the signed blob
+ */
+ inline const char*
+ signed_buf () const;
+
+ /**
+ * @brief Get size of the signed blob
+ */
+ inline size_t
+ signed_size () const;
+
+private:
+ const_iterator m_signedBegin;
+ const_iterator m_signedEnd;
+};
+
+
+inline void
+SignedBlob::setSignedPortion (size_t offset, size_t size)
+{
+ m_signedBegin = begin () + offset;
+ m_signedEnd = begin () + offset + size;
+}
+
+inline SignedBlob::const_iterator
+SignedBlob::signed_begin () const
+{
+ return m_signedBegin;
+}
+
+inline SignedBlob::const_iterator
+SignedBlob::signed_end () const
+{
+ return m_signedEnd;
+}
+
+inline const char*
+SignedBlob::signed_buf () const
+{
+ return &*m_signedBegin;
+}
+
+inline size_t
+SignedBlob::signed_size () const
+{
+ return m_signedEnd - m_signedBegin;
+}
+
+
+} // ndn
+
+#endif // NDN_SIGNED_BLOB_H
diff --git a/ndn-cpp/helpers/hash.cc b/ndn-cpp/helpers/hash.cc
new file mode 100644
index 0000000..0ecf927
--- /dev/null
+++ b/ndn-cpp/helpers/hash.cc
@@ -0,0 +1,130 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ * Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#include "hash.h"
+#include "ndn-cpp/helpers/uri.h"
+
+#include <boost/lexical_cast.hpp>
+#include <openssl/evp.h>
+#include <fstream>
+
+using namespace boost;
+using namespace std;
+
+// Other options: VP_md2, EVP_md5, EVP_sha, EVP_sha1, EVP_sha256, EVP_dss, EVP_dss1, EVP_mdc2, EVP_ripemd160
+#define HASH_FUNCTION EVP_sha256
+
+namespace ndn
+{
+
+std::ostream &
+operator << (std::ostream &os, const Hash &hash)
+{
+ if (hash.m_length == 0)
+ return os;
+
+ ostreambuf_iterator<char> out_it (os); // ostream iterator
+ // need to encode to base64
+ copy (detail::string_from_binary (reinterpret_cast<const char*> (hash.m_buf)),
+ detail::string_from_binary (reinterpret_cast<const char*> (hash.m_buf+hash.m_length)),
+ out_it);
+
+ return os;
+}
+
+std::string
+Hash::shortHash () const
+{
+ return lexical_cast<string> (*this).substr (0, 10);
+}
+
+
+unsigned char Hash::_origin = 0;
+HashPtr Hash::Origin(new Hash(&Hash::_origin, sizeof(unsigned char)));
+
+HashPtr
+Hash::FromString (const std::string &hashInTextEncoding)
+{
+ HashPtr retval = make_shared<Hash> (reinterpret_cast<void*> (0), 0);
+
+ if (hashInTextEncoding.size () == 0)
+ {
+ return retval;
+ }
+
+ if (hashInTextEncoding.size () > EVP_MAX_MD_SIZE * 2)
+ {
+ cerr << "Input hash is too long. Returning an empty hash" << endl;
+ return retval;
+ }
+
+ retval->m_buf = new unsigned char [EVP_MAX_MD_SIZE];
+
+ unsigned char *end = copy (detail::string_to_binary (hashInTextEncoding.begin ()),
+ detail::string_to_binary (hashInTextEncoding.end ()),
+ retval->m_buf);
+
+ retval->m_length = end - retval->m_buf;
+
+ return retval;
+}
+
+HashPtr
+Hash::FromFileContent (const char *filename)
+{
+ HashPtr retval = make_shared<Hash> (reinterpret_cast<void*> (0), 0);
+ retval->m_buf = new unsigned char [EVP_MAX_MD_SIZE];
+
+ EVP_MD_CTX *hash_context = EVP_MD_CTX_create ();
+ EVP_DigestInit_ex (hash_context, HASH_FUNCTION (), 0);
+
+ ifstream iff (filename, std::ios::in | std::ios::binary);
+ while (iff.good ())
+ {
+ char buf[1024];
+ iff.read (buf, 1024);
+ EVP_DigestUpdate (hash_context, buf, iff.gcount ());
+ }
+
+ retval->m_buf = new unsigned char [EVP_MAX_MD_SIZE];
+
+ EVP_DigestFinal_ex (hash_context,
+ retval->m_buf, &retval->m_length);
+
+ EVP_MD_CTX_destroy (hash_context);
+
+ return retval;
+}
+
+HashPtr
+Hash::FromBytes (const ndn::Bytes &bytes)
+{
+ HashPtr retval = make_shared<Hash> (reinterpret_cast<void*> (0), 0);
+ retval->m_buf = new unsigned char [EVP_MAX_MD_SIZE];
+
+ EVP_MD_CTX *hash_context = EVP_MD_CTX_create ();
+ EVP_DigestInit_ex (hash_context, HASH_FUNCTION (), 0);
+
+ // not sure whether it's bad to do so if bytes.size is huge
+ EVP_DigestUpdate(hash_context, ndn::head(bytes), bytes.size());
+
+ retval->m_buf = new unsigned char [EVP_MAX_MD_SIZE];
+
+ EVP_DigestFinal_ex (hash_context,
+ retval->m_buf, &retval->m_length);
+
+ EVP_MD_CTX_destroy (hash_context);
+
+ return retval;
+}
+
+} // ndn
diff --git a/ndn-cpp/helpers/hash.h b/ndn-cpp/helpers/hash.h
new file mode 100644
index 0000000..1652f2b
--- /dev/null
+++ b/ndn-cpp/helpers/hash.h
@@ -0,0 +1,162 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ * Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#ifndef NDN_HASH_H
+#define NDN_HASH_H
+
+#include <string.h>
+#include <iostream>
+#include <boost/shared_ptr.hpp>
+#include <boost/exception/all.hpp>
+
+#include "ndn-cpp/common.h"
+
+namespace ndn
+{
+
+class Hash;
+typedef boost::shared_ptr<Hash> HashPtr;
+
+class Hash
+{
+public:
+ static unsigned char _origin;
+ static HashPtr Origin;
+
+ Hash ()
+ : m_buf(0)
+ , m_length(0)
+ {
+ }
+
+ Hash (const void *buf, unsigned int length)
+ : m_length (length)
+ {
+ if (m_length != 0)
+ {
+ m_buf = new unsigned char [length];
+ memcpy (m_buf, buf, length);
+ }
+ }
+
+ Hash (const Hash &otherHash)
+ : m_length (otherHash.m_length)
+ {
+ if (m_length != 0)
+ {
+ m_buf = new unsigned char [m_length];
+ memcpy (m_buf, otherHash.m_buf, otherHash.m_length);
+ }
+ }
+
+ static HashPtr
+ FromString (const std::string &hashInTextEncoding);
+
+ static HashPtr
+ FromFileContent (const char *fileName);
+
+ static HashPtr
+ FromBytes (const ndn::Bytes &bytes);
+
+ ~Hash ()
+ {
+ if (m_length != 0)
+ delete [] m_buf;
+ }
+
+ Hash &
+ operator = (const Hash &otherHash)
+ {
+ if (m_length != 0)
+ delete [] m_buf;
+
+ m_length = otherHash.m_length;
+ if (m_length != 0)
+ {
+ m_buf = new unsigned char [m_length];
+ memcpy (m_buf, otherHash.m_buf, otherHash.m_length);
+ }
+ return *this;
+ }
+
+ bool
+ IsZero () const
+ {
+ return m_length == 0 ||
+ (m_length == 1 && m_buf[0] == 0);
+ }
+
+ bool
+ operator == (const Hash &otherHash) const
+ {
+ if (m_length != otherHash.m_length)
+ return false;
+
+ return memcmp (m_buf, otherHash.m_buf, m_length) == 0;
+ }
+
+ bool operator < (const Hash &otherHash) const
+ {
+ if (m_length < otherHash.m_length)
+ return true;
+
+ if (m_length > otherHash.m_length)
+ return false;
+
+ for (unsigned int i = 0; i < m_length; i++)
+ {
+ if (m_buf [i] < otherHash.m_buf [i])
+ return true;
+
+ if (m_buf [i] > otherHash.m_buf [i])
+ return false;
+
+ // if equal, continue
+ }
+
+ return false;
+ }
+
+ const void *
+ GetHash () const
+ {
+ return m_buf;
+ }
+
+ unsigned int
+ GetHashBytes () const
+ {
+ return m_length;
+ }
+
+ std::string
+ shortHash () const;
+
+private:
+ unsigned char *m_buf;
+ unsigned int m_length;
+
+ friend std::ostream &
+ operator << (std::ostream &os, const Hash &digest);
+};
+
+namespace Error {
+struct HashConversion : virtual boost::exception, virtual std::exception { };
+}
+
+
+std::ostream &
+operator << (std::ostream &os, const Hash &digest);
+
+}
+
+#endif // NDN_HASH_H
diff --git a/ndn-cpp/helpers/uri.h b/ndn-cpp/helpers/uri.h
new file mode 100644
index 0000000..3fbda7c
--- /dev/null
+++ b/ndn-cpp/helpers/uri.h
@@ -0,0 +1,155 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_DETAIL_URI_H
+#define NDN_DETAIL_URI_H
+
+#include "ndn-cpp/error.h"
+
+#include <boost/archive/iterators/transform_width.hpp>
+#include <boost/iterator/transform_iterator.hpp>
+
+namespace ndn
+{
+
+namespace detail
+{
+
+static const bool ESCAPE_CHARACTER [256] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 26
+ 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 53
+ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 107
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 134
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 161
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 188
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 215
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 242
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 255
+};
+
+/// @cond include_hidden
+template<class CharType>
+struct hex_from_4_bit
+{
+ typedef CharType result_type;
+ CharType operator () (CharType ch) const
+ {
+ const char lookup_table [16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+ // cout << "New character: " << (int) ch << " (" << (char) ch << ")" << "\n";
+ BOOST_ASSERT (ch < 16);
+ return lookup_table[static_cast<size_t>(ch)];
+ }
+};
+
+typedef boost::transform_iterator<hex_from_4_bit<std::string::const_iterator::value_type>,
+ boost::archive::iterators::transform_width<std::string::const_iterator, 4, 8, std::string::const_iterator::value_type> > string_from_binary;
+
+
+
+template<class CharType>
+struct hex_to_4_bit
+{
+ typedef CharType result_type;
+ CharType operator () (CharType ch) const
+ {
+ const signed char lookup_table [] = {
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
+ -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+ };
+
+ signed char value = -1;
+ if ((unsigned)ch < 128)
+ value = lookup_table [(unsigned)ch];
+ if (value == -1)
+ boost::throw_exception (error::StringTransform ());
+
+ return value;
+ }
+};
+
+typedef boost::archive::iterators::transform_width<boost::transform_iterator<hex_to_4_bit<std::string::const_iterator::value_type>, std::string::const_iterator>, 8, 4> string_to_binary;
+/// @endcond
+
+} // detail
+
+/**
+ * @brief A helper class to convert to/from URI
+ */
+class Uri
+{
+public:
+ template<class Iterator1, class Iterator2>
+ inline static void
+ fromEscaped (Iterator1 begin, Iterator1 end, Iterator2 inserter)
+ {
+ Iterator1 i = begin;
+ while (i != end)
+ {
+ if (*i == '%')
+ {
+ try
+ {
+ ++i;
+ Iterator1 j = i;
+ advance (i, 2);
+
+ std::copy (detail::string_to_binary (j), detail::string_to_binary (i), inserter);
+ }
+ catch (ndn::error::StringTransform &e)
+ {
+ BOOST_THROW_EXCEPTION (error::Uri ()
+ << error::pos (std::distance (i, begin)));
+ }
+ }
+ else if (!detail::ESCAPE_CHARACTER[static_cast<unsigned char> (*i)])
+ {
+ *inserter = *i;
+ ++inserter; ++i;
+ }
+ else
+ {
+ BOOST_THROW_EXCEPTION (error::Uri ()
+ << error::pos (std::distance (i, begin)));
+ }
+ }
+ }
+
+ template<class Iterator1, class Iterator2>
+ inline static void
+ toEscaped (Iterator1 begin, Iterator1 end, Iterator2 inserter)
+ {
+ const char lookup_table [16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+ for (Iterator1 i = begin; i != end; i++)
+ {
+ if (detail::ESCAPE_CHARACTER[static_cast<unsigned char> (*i)])
+ {
+ *inserter = '%'; ++inserter;
+ *inserter = lookup_table [(*i >> 4) & 0x0F]; ++inserter;
+ *inserter = lookup_table [(*i & 0x0F)]; ++inserter;
+ }
+ else
+ {
+ *inserter = *i; ++inserter;
+ }
+ }
+ }
+};
+
+} // ndn
+
+#endif // NDN_DETAIL_URI_H
diff --git a/ndn-cpp/interest.cc b/ndn-cpp/interest.cc
new file mode 100644
index 0000000..3825677
--- /dev/null
+++ b/ndn-cpp/interest.cc
@@ -0,0 +1,103 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ * Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#include "interest.h"
+#include <boost/lexical_cast.hpp>
+
+using namespace std;
+
+namespace ndn {
+
+Interest::Interest ()
+ // m_name
+ : m_maxSuffixComponents (Interest::ncomps)
+ , m_minSuffixComponents (Interest::ncomps)
+ , m_answerOriginKind (AOK_DEFAULT)
+ , m_interestLifetime (time::Seconds (-1.0))
+ , m_scope (NO_SCOPE)
+ , m_childSelector (CHILD_DEFAULT)
+ // m_publisherKeyDigest
+{
+}
+
+Interest::Interest (const Name &name)
+ : m_name (name)
+ , m_maxSuffixComponents (Interest::ncomps)
+ , m_minSuffixComponents (Interest::ncomps)
+ , m_answerOriginKind(AOK_DEFAULT)
+ , m_interestLifetime (time::Seconds (-1.0))
+ , m_scope (NO_SCOPE)
+ , m_childSelector (CHILD_DEFAULT)
+ // m_publisherKeyDigest
+{
+}
+
+Interest::Interest (const Interest &other)
+{
+ m_name = other.m_name;
+ m_maxSuffixComponents = other.m_maxSuffixComponents;
+ m_minSuffixComponents = other.m_minSuffixComponents;
+ m_answerOriginKind = other.m_answerOriginKind;
+ m_interestLifetime = other.m_interestLifetime;
+ m_scope = other.m_scope;
+ m_childSelector = other.m_childSelector;
+ m_publisherPublicKeyDigest = other.m_publisherPublicKeyDigest;
+}
+
+Interest::Interest (const ccn_parsed_interest *pi)
+ : m_maxSuffixComponents (Interest::ncomps)
+ , m_minSuffixComponents (Interest::ncomps)
+ , m_answerOriginKind (AOK_DEFAULT)
+ , m_interestLifetime (time::Seconds (-1.0))
+ , m_scope (NO_SCOPE)
+ , m_childSelector (CHILD_DEFAULT)
+{
+ if (pi != NULL)
+ {
+ m_maxSuffixComponents = pi->max_suffix_comps;
+ m_minSuffixComponents = pi->min_suffix_comps;
+ switch(pi->orderpref)
+ {
+ case 0: m_childSelector = CHILD_LEFT; break;
+ case 1: m_childSelector = CHILD_RIGHT; break;
+ default: m_childSelector = CHILD_DEFAULT; break;
+ }
+
+ switch(pi->answerfrom)
+ {
+ case 0x1: m_answerOriginKind = AOK_CS; break;
+ case 0x2: m_answerOriginKind = AOK_NEW; break;
+ case 0x3: m_answerOriginKind = AOK_DEFAULT; break;
+ case 0x4: m_answerOriginKind = AOK_STALE; break;
+ case 0x10: m_answerOriginKind = AOK_EXPIRE; break;
+ default: break;
+ }
+ m_scope = static_cast<Scope> (pi->scope);
+ }
+
+ /// @todo copy publisher key digest
+}
+
+bool
+Interest::operator == (const Interest &other)
+{
+ return
+ m_name == other.m_name
+ && m_maxSuffixComponents == other.m_maxSuffixComponents
+ && m_minSuffixComponents == other.m_minSuffixComponents
+ && m_answerOriginKind == other.m_answerOriginKind
+ && m_interestLifetime == other.m_interestLifetime
+ && m_scope == other.m_scope
+ && m_childSelector == other.m_childSelector;
+}
+
+} // ndn
diff --git a/ndn-cpp/interest.h b/ndn-cpp/interest.h
new file mode 100644
index 0000000..d929efa
--- /dev/null
+++ b/ndn-cpp/interest.h
@@ -0,0 +1,461 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ * Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ */
+
+#ifndef NDN_INTEREST_H
+#define NDN_INTEREST_H
+
+#include <ndn-cpp/common.h>
+#include <ndn-cpp/fields/name.h>
+#include <ndn-cpp/fields/exclude.h>
+#include <ndn-cpp/helpers/hash.h>
+
+namespace ndn {
+
+/**
+ * @brief Class abstracting operations with Interests (constructing and getting access to Interest fields)
+ */
+class Interest
+{
+public:
+ /**
+ * @brief Default constructor, creates an interest for / prefix without any selectors
+ */
+ Interest ();
+
+ /**
+ * @brief Create an interest for the name
+ * @param name name of the data to request
+ */
+ Interest (const Name &name);
+
+ /**
+ * @brief Copy constructor
+ * @param interest interest to copy
+ */
+ Interest (const Interest &interest);
+
+ /**
+ * @brief Create an interest based on ccn_parsed_interest data structure
+ * @param interest pointer to ccn_parsed_interest data structure
+ *
+ * This method will create an interest with empty name, since ccn_parsed_interest structure
+ * has limited amount of information
+ */
+ Interest (const ccn_parsed_interest *interest);
+
+ /**
+ * @brief Set interest name
+ * @param name name of the interest
+ * @return reference to self (to allow method chaining)
+ *
+ * In some cases, a direct access to and manipulation of name using getName is more efficient
+ */
+ inline Interest &
+ setName (const Name &name);
+
+ /**
+ * @brief Get interest name (const reference)
+ * @returns name of the interest
+ */
+ inline const Name &
+ getName () const;
+
+ /**
+ * @brief Get interest name (reference)
+ * @returns name of the interest
+ */
+ inline Name &
+ getName ();
+
+ /**
+ * @brief Set interest lifetime (time_duration)
+ * @param interestLifetime interest lifetime specified as a time_duration value.
+ * Negative value means that InterestLifetime is not set.
+ * @return reference to self (to allow method chaining)
+ */
+ inline Interest &
+ setInterestLifetime (const TimeInterval &interestLifetime);
+
+ /**
+ * @brief Set interest lifetime (double)
+ * @param interestLifetime interest lifetime expressed in seconds, with possible fractional seconds (double).
+ * Negative value means that InterestLifetime is not set.
+ * @return reference to self (to allow method chaining)
+ */
+ inline Interest &
+ setInterestLifetime (double interestLifetimeSeconds);
+
+ /**
+ * @brief Get interest lifetime
+ * @return TimeInterval representing lifetime of the interest.
+ * Use time_duration::total_seconds () or time_duration::total_microseconds (),
+ * if you need interest lifetime as a plain number.
+ * @see http://www.boost.org/doc/libs/1_53_0/doc/html/date_time/posix_time.html
+ */
+ inline const TimeInterval &
+ getInterestLifetime () const;
+
+ /**
+ * @brief Set intended interest scope
+ * @param scope requested scope of the interest @see Scope
+ * @return reference to self (to allow method chaining)
+ */
+ inline Interest &
+ setScope (uint8_t scope);
+
+ /**
+ * @brief Get intended interest scope
+ * @return intended interest scope @see Scope
+ */
+ inline uint8_t
+ getScope () const;
+
+ ///////////////////////////////////////////////////////////////////////
+ // SELECTORS //
+ ///////////////////////////////////////////////////////////////////////
+
+ /**
+ * @brief Enum defining constants for AnswerOriginKind selector field
+ */
+ enum AnswerOriginKind
+ {
+ AOK_CS = 0x1, ///< @brief request item from the content store
+ AOK_NEW = 0x2, ///< @brief request item from the original producer
+ AOK_DEFAULT = 0x3, ///< @brief default: either from content store or original producer
+ AOK_STALE = 0x4, ///< @brief Allow stale data
+ AOK_EXPIRE = 0x10 ///< @brief Allow expired data (?)
+ };
+
+ /**
+ * @brief Enum defining constants for ChildSelector field
+ */
+ enum ChildSelector
+ {
+ CHILD_LEFT = 0, ///< @brief request left child
+ CHILD_RIGHT = 1, ///< @brief request right child
+ CHILD_DEFAULT = 2 ///< @brief do not specify which child is requested
+ };
+
+ /**
+ * @brief Enum defining constants for Scope field
+ */
+ enum Scope
+ {
+ NO_SCOPE = 255, ///< @brief Interest scope is not defined
+ SCOPE_LOCAL_CCND = 0, ///< @brief Interest scope is only toward local NDN daemon
+ SCOPE_LOCAL_HOST = 1, ///< @brief Interest scope is within local host (any local application only)
+ SCOPE_NEXT_HOST = 2 ///< @brief Interest scope is within local host and immediate neighboring node
+ };
+
+ /**
+ * @brief Set interest selector for maximum suffix components
+ * @param maxSuffixComponents maximum number of suffix components. If Interest::ncomps, then not restricted
+ * @return reference to self (to allow method chaining)
+ */
+ inline Interest &
+ setMaxSuffixComponents (uint32_t maxSuffixComponents);
+
+ /**
+ * \brief Get interest selector for maximum suffix components
+ *
+ * MaxSuffixComponents refer to the number of name components beyond those in the prefix,
+ * and counting the implicit digest, that may occur in the matching ContentObject.
+ * For more information, see http://www.ccnx.org/releases/latest/doc/technical/InterestMessage.html
+ **/
+ inline uint32_t
+ getMaxSuffixComponents () const;
+
+ /**
+ * @brief Set interest selector for minimum suffix components
+ * @param minSuffixComponents minimum number of suffix components. If Interest::ncomps, then not restricted
+ * @return reference to self (to allow method chaining)
+ */
+ inline Interest &
+ setMinSuffixComponents (uint32_t minSuffixComponents);
+
+ /**
+ * \brief Get interest selector for minimum suffix components
+ *
+ * MinSuffixComponents refer to the number of name components beyond those in the prefix,
+ * and counting the implicit digest, that may occur in the matching ContentObject.
+ * For more information, see http://www.ccnx.org/releases/latest/doc/technical/InterestMessage.html
+ **/
+ inline uint32_t
+ getMinSuffixComponents () const;
+
+ /**
+ * @brief Set interest selector for answer origin kind
+ * @param answerOriginKind type of answer @see AnswerOriginKind
+ * @return reference to self (to allow method chaining)
+ */
+ inline Interest &
+ setAnswerOriginKind (uint32_t answerOriginKind);
+
+ /**
+ * @brief Get interest selector for answer origin kind
+ */
+ inline uint32_t
+ getAnswerOriginKind () const;
+
+ /**
+ * @brief Set interest selector for child selector
+ * @param child child selector @see ChildSelector
+ * @return reference to self (to allow method chaining)
+ *
+ * Often a given interest will match more than one ContentObject within a given content store.
+ * The ChildSelector provides a way of expressing a preference for which of these should be returned.
+ * If the value is false, the leftmost child is preferred. If true, the rightmost child is preferred.
+ * \see http://www.ccnx.org/releases/latest/doc/technical/InterestMessage.html for more information.
+ */
+ inline Interest &
+ setChildSelector (uint8_t child);
+
+ /**
+ * @brief Get interest selector for child selector
+ */
+ inline uint8_t
+ getChildSelector () const;
+
+ /**
+ * @brief Set interest selector for publisher public key digest
+ * @param digest publisher public key digest
+ * @return reference to self (to allow method chaining)
+ *
+ * Currently, this method has no effect
+ * @todo Implement PublisherPublicKeyDigest
+ */
+ inline Interest &
+ setPublisherPublicKeyDigest(const Hash &digest);
+
+ /**
+ * @brief Get interest selector for publisher public key digest
+ *
+ * @todo Implement
+ */
+ inline const Hash&
+ getPublisherPublicKeyDigest () const;
+
+ /**
+ * @brief Set exclude filter
+ * @param exclude An exclude filter to set
+ *
+ * In some cases, a direct access to and manipulation of exclude filter using getExclude is more efficient
+ */
+ inline void
+ setExclude (const Exclude &exclude);
+
+ /**
+ * @brief Get exclude filter (const reference)
+ */
+ inline const Exclude &
+ getExclude () const;
+
+ /**
+ * @brief Get exclude filter (reference)
+ */
+ inline Exclude &
+ getExclude ();
+
+ ///////////////////////////////////////////////////////////////////////
+ // HELPERS //
+ ///////////////////////////////////////////////////////////////////////
+
+ /**
+ * @brief Compare equality of two interests
+ */
+ bool
+ operator== (const Interest &interest);
+
+public:
+ // Data Members (public):
+ /// @brief Value indicating that number of components parameter is invalid
+ const static uint32_t ncomps = static_cast<uint32_t> (-1);
+
+private:
+ Name m_name;
+ uint32_t m_maxSuffixComponents;
+ uint32_t m_minSuffixComponents;
+ uint32_t m_answerOriginKind;
+ TimeInterval m_interestLifetime; // lifetime in seconds
+
+ uint8_t m_scope;
+ uint8_t m_childSelector;
+ // not used now
+ Hash m_publisherPublicKeyDigest;
+ Exclude m_exclude;
+
+ Ptr<Blob> m_wire;
+};
+
+typedef boost::shared_ptr<Interest> InterestPtr;
+
+namespace Error
+{
+/**
+ * @brief Exception that is thrown in case of error during interest construction or parsing
+ */
+struct Interest:
+ virtual boost::exception, virtual std::exception {};
+}
+
+
+
+inline Interest &
+Interest::setName (const Name &name)
+{
+ m_name = name;
+ return *this;
+}
+
+inline const Name &
+Interest::getName () const
+{
+ return m_name;
+}
+
+inline Name &
+Interest::getName ()
+{
+ return m_name;
+}
+
+inline Interest &
+Interest::setInterestLifetime (const TimeInterval &interestLifetime)
+{
+ m_interestLifetime = interestLifetime;
+ return *this;
+}
+
+inline Interest &
+Interest::setInterestLifetime (double interestLifetimeSeconds)
+{
+ m_interestLifetime = time::Seconds (interestLifetimeSeconds);
+ return *this;
+}
+
+inline const TimeInterval &
+Interest::getInterestLifetime () const
+{
+ return m_interestLifetime;
+}
+
+inline Interest &
+Interest::setScope (uint8_t scope)
+{
+ m_scope = scope;
+ return *this;
+}
+
+inline uint8_t
+Interest::getScope () const
+{
+ return m_scope;
+}
+
+///////////////////////////////////////////////////////////////////////
+// SELECTORS //
+///////////////////////////////////////////////////////////////////////
+
+
+inline Interest &
+Interest::setMaxSuffixComponents (uint32_t maxSuffixComponents)
+{
+ m_maxSuffixComponents = maxSuffixComponents;
+ return *this;
+}
+
+inline uint32_t
+Interest::getMaxSuffixComponents () const
+{
+ return m_maxSuffixComponents;
+}
+
+inline Interest &
+Interest::setMinSuffixComponents (uint32_t minSuffixComponents)
+{
+ m_minSuffixComponents = minSuffixComponents;
+ return *this;
+}
+
+inline uint32_t
+Interest::getMinSuffixComponents () const
+{
+ return m_minSuffixComponents;
+}
+
+inline Interest &
+Interest::setAnswerOriginKind (uint32_t answerOriginKind)
+{
+ m_answerOriginKind = answerOriginKind;
+ return *this;
+}
+
+inline uint32_t
+Interest::getAnswerOriginKind () const
+{
+ return m_answerOriginKind;
+}
+
+inline Interest &
+Interest::setChildSelector (uint8_t childSelector)
+{
+ m_childSelector = childSelector;
+ return *this;
+}
+
+inline uint8_t
+Interest::getChildSelector () const
+{
+ return m_childSelector;
+}
+
+inline Interest &
+Interest::setPublisherPublicKeyDigest(const Hash &publisherPublicKeyDigest)
+{
+ m_publisherPublicKeyDigest = publisherPublicKeyDigest;
+ return *this;
+}
+
+inline const Hash&
+Interest::getPublisherPublicKeyDigest () const
+{
+ return m_publisherPublicKeyDigest;
+}
+
+inline void
+Interest::setExclude (const Exclude &exclude)
+{
+ m_exclude = exclude;
+}
+
+/**
+ * @brief Get exclude filter (const reference)
+ */
+inline const Exclude &
+Interest::getExclude () const
+{
+ return m_exclude;
+}
+
+/**
+ * @brief Get exclude filter (reference)
+ */
+inline Exclude &
+Interest::getExclude ()
+{
+ return m_exclude;
+}
+
+
+} // ndn
+
+#endif // NDN_INTEREST_H
diff --git a/ndn-cpp/security/certificate.h b/ndn-cpp/security/certificate.h
new file mode 100644
index 0000000..e0efa91
--- /dev/null
+++ b/ndn-cpp/security/certificate.h
@@ -0,0 +1,43 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_CERTIFICATE_H
+#define NDN_CERTIFICATE_H
+
+#include "ndn-cpp/data.h"
+
+namespace ndn {
+
+/**
+ * @brief Class representing NDN identity
+ *
+ * - name
+ * - full NDN name of the NDN certificate
+ * - /ndn/ucla.edu/alex/cert/<pubkey.sha256>/<issuer>
+ * - content
+ * - X.509 certificate in DER format (X.509 certificate can include any necessary identity information, as well as is fully extendable)
+ * - Subject:
+ * - full real name, associated with the certificate
+ * - full affiliation, associated with the certificate
+ * - Subject Public Key Info
+ * - Validity
+ * - signature
+ * - issuerCertName (KeyLocator/CertName)
+ * - /ndn/ucla.edu/cert/<pubkey.sha256>/<issuer>
+ *
+ */
+class Certificate : public Data
+{
+public:
+};
+
+} // ndn
+
+#endif // NDN_CERTIFICATE_H
diff --git a/ndn-cpp/security/identity.h b/ndn-cpp/security/identity.h
new file mode 100644
index 0000000..676b3b3
--- /dev/null
+++ b/ndn-cpp/security/identity.h
@@ -0,0 +1,46 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_IDENTITY_H
+#define NDN_IDENTITY_H
+
+namespace ndn {
+
+/**
+ * @brief Class representing NDN identity
+ *
+ * - name
+ * - (indexing and lookup)
+ * - /ndn/ucla.edu/alex
+ * - contents
+ * - privateKeyName
+ * - unique name of the private key
+ * - private key bits are not exposed anywhere
+ * - /ndn/ucla.edu/alex/privKey/<pubkey.sha256>
+ * - indexed list of certificates
+ * - NDN DATA packets
+ * - easy access data structure of NDN certificate (“parsed DATA packet”)
+ * - link to default certificate
+ * - revocation list
+ * - one or more NDN DATA packets
+ * - name: <identity-name>/revocation-list/<version>(/<seqno>)?
+ * - /ndn/ucla.edu/alex/revocation-list/%FD...01
+ * - initially empty, updated whenever an issued certificate is getting revoked
+ * - revocation always exists
+ *
+ */
+class Identity
+{
+public:
+};
+
+} // ndn
+
+#endif // NDN_IDENTITY_H
diff --git a/ndn-cpp/security/keychain-pkcs12.cc b/ndn-cpp/security/keychain-pkcs12.cc
new file mode 100644
index 0000000..8a01fd5
--- /dev/null
+++ b/ndn-cpp/security/keychain-pkcs12.cc
@@ -0,0 +1,69 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "keychain-pkcs12.h"
+
+namespace ndn {
+
+/////////////////////////////////////////////////////
+// interface to manage certificates and identities //
+/////////////////////////////////////////////////////
+
+Ptr<const Identity>
+KeychainKeystoreOpenssl::getDefaultIdentity ()
+{
+ return Ptr<const Identity> ();
+}
+
+Ptr<const Identity>
+KeychainKeystoreOpenssl::getIdentity (const Name &identityName)
+{
+ return Ptr<const Identity> ();
+}
+
+Ptr<const Identity>
+KeychainKeystoreOpenssl::generateIdentity (const Name &identityName)
+{
+ return Ptr<const Identity> ();
+}
+
+void
+KeychainKeystoreOpenssl::requestIdentityCertificate (const Identity &identity, std::ostream &os)
+{
+}
+
+Ptr<const Certificate>
+KeychainKeystoreOpenssl::issueCertificate (const Identity &identity, std::istream &is)
+{
+ return Ptr<const Certificate> ();
+}
+
+Ptr<const Certificate>
+KeychainKeystoreOpenssl::issueCertificate (std::istream &is)
+{
+ return Ptr<const Certificate> ();
+}
+
+void
+KeychainKeystoreOpenssl::installIdentityCertificate (const Certificate &cert)
+{
+}
+
+/////////////////////////////////////////////////////
+// interface to sign and encrypt data //
+/////////////////////////////////////////////////////
+Ptr<Signature>
+KeychainKeystoreOpenssl::sign (const Identity &identity, const void *buffer, size_t size)
+{
+ return Ptr<Signature> ();
+}
+
+
+} // ndn
diff --git a/ndn-cpp/security/keychain-pkcs12.h b/ndn-cpp/security/keychain-pkcs12.h
new file mode 100644
index 0000000..898d792
--- /dev/null
+++ b/ndn-cpp/security/keychain-pkcs12.h
@@ -0,0 +1,74 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_KEYCHAIN_PKCS12_H
+#define NDN_KEYCHAIN_PKCS12_H
+
+#include "keychain.h"
+#include "ndn-cpp/helpers/hash.h"
+
+namespace ndn
+{
+
+/**
+ * @brief Class implementing logic to work with pkcs12 CCNx keystore file (.ccnx_keystore)
+ */
+class KeychainKeystoreOpenssl : public virtual Keychain
+{
+public:
+ KeychainKeystoreOpenssl ();
+ KeychainKeystoreOpenssl (const std::string &path);
+
+public:
+ /////////////////////////////////////////////////////
+ // interface to manage certificates and identities //
+ /////////////////////////////////////////////////////
+
+ virtual Ptr<const Identity>
+ getDefaultIdentity ();
+
+ virtual Ptr<const Identity>
+ getIdentity (const Name &identityName);
+
+ virtual Ptr<const Identity>
+ generateIdentity (const Name &identityName);
+
+ virtual void
+ requestIdentityCertificate (const Identity &identity, std::ostream &os);
+
+ virtual Ptr<const Certificate>
+ issueCertificate (const Identity &identity, std::istream &is);
+
+ virtual Ptr<const Certificate>
+ issueCertificate (std::istream &is);
+
+ virtual void
+ installIdentityCertificate (const Certificate &cert);
+
+public:
+ /////////////////////////////////////////////////////
+ // interface to sign and encrypt data //
+ /////////////////////////////////////////////////////
+ virtual Ptr<Signature>
+ sign (const Identity &identity, const void *buffer, size_t size);
+
+
+private:
+ void
+ initialize (const std::string &pkcs12);
+
+private:
+ Name m_publicKeyName;
+ Hash m_publicKeyDigest;
+};
+
+} // ndn
+
+#endif // NDN_KEYCHAIN_KEYSTORE_OPENSSL_H
diff --git a/ndn-cpp/security/keychain.cc b/ndn-cpp/security/keychain.cc
new file mode 100644
index 0000000..2f7fbe5
--- /dev/null
+++ b/ndn-cpp/security/keychain.cc
@@ -0,0 +1,15 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "keychain.h"
+
+ndn::Keychain::~Keychain ()
+{
+}
diff --git a/ndn-cpp/security/keychain.h b/ndn-cpp/security/keychain.h
new file mode 100644
index 0000000..83a09dd
--- /dev/null
+++ b/ndn-cpp/security/keychain.h
@@ -0,0 +1,130 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_KEYCHAIN_H
+#define NDN_KEYCHAIN_H
+
+// #include "ndn-cpp/fields/blob.h"
+// #include "ndn-cpp/fields/name.h"
+
+#include "identity.h"
+#include "certificate.h"
+
+#include <iostream>
+
+namespace ndn {
+
+/**
+ * @brief Interface for a keychain operations
+ *
+ * Keychain has the following set of operations:
+ *
+ * --- interface to manage certificates and identities
+ * - identities are permanently stored
+ * - certificates can be cached (or stored permanently, if user is willing to)
+ * --- interface to sign and encrypt data
+ *
+ */
+class Keychain
+{
+public:
+ /**
+ * @brief Virtual destructor
+ */
+ virtual
+ ~Keychain ();
+
+ /////////////////////////////////////////////////////
+ // interface to manage certificates and identities //
+ /////////////////////////////////////////////////////
+
+ /**
+ * @brief Get default identity
+ */
+ virtual Ptr<const Identity>
+ getDefaultIdentity () = 0;
+
+ /**
+ * @brief Get identity by name
+ * @param identityName name of the requested identity
+ */
+ virtual Ptr<const Identity>
+ getIdentity (const Name &identityName) = 0;
+
+ /**
+ * @brief Create a self-certified identity
+ * @param identityName name of the identity to create
+ */
+ virtual Ptr<const Identity>
+ generateIdentity (const Name &identityName) = 0;
+
+ /**
+ * @brief Create identity certification request
+ * @param identity identity for which create the request
+ * @param os output stream which will receive the request
+ */
+ virtual void
+ requestIdentityCertificate (const Identity &identity, std::ostream &os) = 0;
+
+ /**
+ * @brief Issue a certificate using parameters from the input stream (formatted as request)
+ * @param identity Identity which will be used to issue the certificate
+ * @param is input stream from which to read parameters of the certificate
+ *
+ * @returns smart pointer to a signed certificate
+ */
+ virtual Ptr<const Certificate>
+ issueCertificate (const Identity &identity, std::istream &is) = 0;
+
+ /**
+ * @brief Issue a certificate using parameters from the input stream (formatted as request)
+ *
+ * Same as another version, but using the default identity
+ *
+ * @returns smart pointer to a signed certificate
+ */
+ virtual Ptr<const Certificate>
+ issueCertificate (std::istream &is) = 0;
+
+ /**
+ * @brief Install identity certificate
+ * @param cert certificate to install
+ */
+ virtual void
+ installIdentityCertificate (const Certificate &cert) = 0;
+
+public:
+ /////////////////////////////////////////////////////
+ // interface to sign and encrypt data //
+ /////////////////////////////////////////////////////
+
+ /**
+ * @brief Sign data using specified identity
+ * @param identity selected identity to sign data
+ * @param buffer pointer to the data to sign
+ * @param size length of data to sign
+ *
+ * @return pointer to base class of a signature object (depending on identity,
+ * different types signature can be produced)
+ */
+ virtual Ptr<Signature>
+ sign (const Identity &identity, const void *buffer, size_t size) = 0;
+
+ // TBD
+ // /**
+ // * @brief Decrypt data using the specified identity
+ // */
+ // virtual ?
+ // decrypt (Ptr<Identity> identity, const void *buffer, size_t size, ?) = 0;
+};
+
+} // ndn
+
+#endif // NDN_KEYCHAIN_H
diff --git a/ndn-cpp/security/verifier.h b/ndn-cpp/security/verifier.h
new file mode 100644
index 0000000..cb98243
--- /dev/null
+++ b/ndn-cpp/security/verifier.h
@@ -0,0 +1,38 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_VERIFIER_H
+#define NDN_VERIFIER_H
+
+namespace ndn {
+
+/**
+ * @brief Interface for NDN DATA packet verification (trust model)
+ *
+ * --- interface to verify DATA packets
+ * - application selects required implementation
+ * - at least two build-in models:
+ * = hierarchical (default)
+ * = simple chain (without authorization)
+ * - uses NDN keychain as a backend to cache certificates
+ */
+class Verifier
+{
+public:
+ /**
+ * @brief Virtual destructor
+ */
+ virtual
+ ~Verifier ();
+};
+
+} // ndn
+
+#endif // NDN_VERIFIER_H
diff --git a/ndn-cpp/trie/detail/functor-hook.h b/ndn-cpp/trie/detail/functor-hook.h
new file mode 100644
index 0000000..f34969c
--- /dev/null
+++ b/ndn-cpp/trie/detail/functor-hook.h
@@ -0,0 +1,70 @@
+/* -*- 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: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef FUNCTOR_HOOK_H_
+#define FUNCTOR_HOOK_H_
+
+#include <boost/intrusive/parent_from_member.hpp>
+
+namespace ns3 {
+namespace ndn {
+namespace ndnSIM {
+namespace detail {
+
+template<class BaseHook, class ValueType, int N>
+struct FunctorHook
+{
+ typedef typename BaseHook::template index<N>::type hook_type;
+ typedef hook_type* hook_ptr;
+ typedef const hook_type* const_hook_ptr;
+
+ typedef ValueType value_type;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+
+ //Required static functions
+ static hook_ptr to_hook_ptr (value_type &value)
+ { return &value.policy_hook_.template get<N> (); }
+
+ static const_hook_ptr to_hook_ptr(const value_type &value)
+ { return &value.policy_hook_.template get<N> (); }
+
+ static pointer to_value_ptr(hook_ptr n)
+ {
+ return
+ boost::intrusive::get_parent_from_member<value_type>
+ (static_cast<BaseHook*> (boost::intrusive::get_parent_from_member< wrap<hook_type> >(n, &wrap<hook_type>::value_)),
+ &value_type::policy_hook_);
+ }
+ static const_pointer to_value_ptr(const_hook_ptr n)
+ {
+ return
+ boost::intrusive::get_parent_from_member<value_type>
+ (static_cast<const BaseHook*> (boost::intrusive::get_parent_from_member< wrap<hook_type> >(n, &wrap<hook_type>::value_)),
+ &value_type::policy_hook_);
+ }
+};
+
+} // detail
+} // ndnSIM
+} // ndn
+} // ns3
+
+#endif // FUNCTOR_HOOK_H_
diff --git a/ndn-cpp/trie/detail/multi-policy-container.h b/ndn-cpp/trie/detail/multi-policy-container.h
new file mode 100644
index 0000000..c1251e9
--- /dev/null
+++ b/ndn-cpp/trie/detail/multi-policy-container.h
@@ -0,0 +1,175 @@
+/* -*- 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: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef MULTI_POLICY_CONTAINER_H_
+#define MULTI_POLICY_CONTAINER_H_
+
+#include <boost/mpl/inherit_linearly.hpp>
+#include <boost/mpl/at.hpp>
+
+namespace ns3 {
+namespace ndn {
+namespace ndnSIM {
+namespace detail {
+
+template< class Base, class Value >
+struct policy_wrap
+{
+ policy_wrap (Base &base) : value_ (base) { }
+ Value value_;
+};
+
+template< class Base, class Super/*empy_wrap/previous level*/, class Value/*policy_wrap< element in vector >*/ >
+struct inherit_with_base : Super, Value
+{
+ inherit_with_base (Base &base) : Super (base), Value (base) { }
+
+ void
+ update (typename Base::iterator item)
+ {
+ Value::value_.update (item);
+ Super::update (item);
+ }
+
+ bool
+ insert (typename Base::iterator item)
+ {
+ bool ok = Value::value_.insert (item);
+ if (!ok)
+ return false;
+
+ ok = Super::insert (item);
+ if (!ok)
+ {
+ Value::value_.erase (item);
+ return false;
+ }
+ return true;
+ }
+
+ void
+ lookup (typename Base::iterator item)
+ {
+ Value::value_.lookup (item);
+ Super::lookup (item);
+ }
+
+ void
+ erase (typename Base::iterator item)
+ {
+ Value::value_.erase (item);
+ Super::erase (item);
+ }
+
+ void
+ clear ()
+ {
+ Value::value_.clear ();
+ Super::clear ();
+ }
+};
+
+template< class Base >
+struct empty_policy_wrap
+{
+ empty_policy_wrap (Base &base) { }
+
+ void update (typename Base::iterator item) {}
+ bool insert (typename Base::iterator item) { return true; }
+ void lookup (typename Base::iterator item) {}
+ void erase (typename Base::iterator item) {}
+ void clear () {}
+};
+
+template< class Base, class Vector >
+struct multi_policy_container
+ : public boost::mpl::fold< Vector,
+ empty_policy_wrap<Base>,
+ inherit_with_base<Base,
+ boost::mpl::_1/*empty/previous*/,
+ policy_wrap<Base, boost::mpl::_2>/*element in vector*/>
+ >::type
+{
+ typedef typename boost::mpl::fold< Vector,
+ empty_policy_wrap<Base>,
+ inherit_with_base<Base,
+ boost::mpl::_1/*empty/previous*/,
+ policy_wrap<Base, boost::mpl::_2>/*element in vector*/>
+ >::type super;
+
+ typedef typename boost::mpl::at_c<Vector, 0>::type::iterator iterator;
+ typedef typename boost::mpl::at_c<Vector, 0>::type::const_iterator const_iterator;
+
+ iterator begin () { return this->get<0> ().begin (); }
+ const_iterator begin () const { return this->get<0> ().begin (); }
+
+ iterator end () { return this->get<0> ().end (); }
+ const_iterator end () const { return this->get<0> ().end (); }
+
+ size_t size () const { return this->get<0> ().size (); }
+
+ multi_policy_container (Base &base)
+ : super (base)
+ { }
+
+ template<int N>
+ struct index
+ {
+ typedef typename boost::mpl::at_c<Vector, N>::type type;
+ };
+
+ template<class T>
+ T &
+ get ()
+ {
+ return static_cast< policy_wrap<Base, T> &> (*this).value_;
+ }
+
+ template<class T>
+ const T &
+ get () const
+ {
+ return static_cast< const policy_wrap<Base, T> &> (*this).value_;
+ }
+
+ template<int N>
+ typename boost::mpl::at_c<Vector, N>::type &
+ get ()
+ {
+ typedef typename boost::mpl::at_c<Vector, N>::type T;
+ return static_cast< policy_wrap<Base, T> &> (*this).value_;
+ }
+
+ template<int N>
+ const typename boost::mpl::at_c<Vector, N>::type &
+ get () const
+ {
+ typedef typename boost::mpl::at_c<Vector, N>::type T;
+ return static_cast< const policy_wrap<Base, T> &> (*this).value_;
+ }
+};
+
+
+} // detail
+} // ndnSIM
+} // ndn
+} // ns3
+
+#endif // MULTI_POLICY_CONTAINER_H_
diff --git a/ndn-cpp/trie/detail/multi-type-container.h b/ndn-cpp/trie/detail/multi-type-container.h
new file mode 100644
index 0000000..d4971c4
--- /dev/null
+++ b/ndn-cpp/trie/detail/multi-type-container.h
@@ -0,0 +1,86 @@
+/* -*- 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: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef MULTI_TYPE_CONTAINER_H_
+#define MULTI_TYPE_CONTAINER_H_
+
+#include <boost/mpl/inherit_linearly.hpp>
+#include <boost/mpl/inherit.hpp>
+#include <boost/mpl/at.hpp>
+
+namespace ns3 {
+namespace ndn {
+namespace ndnSIM {
+namespace detail {
+
+template <class T>
+struct wrap
+{
+ T value_;
+};
+
+template< class Vector >
+struct multi_type_container
+ : public boost::mpl::inherit_linearly< Vector, boost::mpl::inherit<wrap<boost::mpl::_2>, boost::mpl::_1 >
+ >::type
+{
+ template<int N>
+ struct index
+ {
+ typedef typename boost::mpl::at_c<Vector, N>::type type;
+ };
+
+ template<class T>
+ T &
+ get ()
+ {
+ return static_cast< wrap<T> &> (*this).value_;
+ }
+
+ template<class T>
+ const T &
+ get () const
+ {
+ return static_cast< const wrap<T> &> (*this).value_;
+ }
+
+ template<int N>
+ typename boost::mpl::at_c<Vector, N>::type &
+ get ()
+ {
+ typedef typename boost::mpl::at_c<Vector, N>::type T;
+ return static_cast< wrap<T> &> (*this).value_;
+ }
+
+ template<int N>
+ const typename boost::mpl::at_c<Vector, N>::type &
+ get () const
+ {
+ typedef typename boost::mpl::at_c<Vector, N>::type T;
+ return static_cast< const wrap<T> &> (*this).value_;
+ }
+};
+
+} // detail
+} // ndnSIM
+} // ndn
+} // ns3
+
+#endif // MULTI_TYPE_CONTAINER_H_
diff --git a/ndn-cpp/trie/payload-traits/pointer.h b/ndn-cpp/trie/payload-traits/pointer.h
new file mode 100644
index 0000000..8290fbe
--- /dev/null
+++ b/ndn-cpp/trie/payload-traits/pointer.h
@@ -0,0 +1,40 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_TRIE_PAYLOAD_TRAITS_POINTER_H
+#define NDN_TRIE_PAYLOAD_TRAITS_POINTER_H
+
+namespace ndn {
+namespace trie {
+
+template<typename Payload, typename BasePayload = Payload>
+struct pointer_payload_traits
+{
+ typedef Payload payload_type; // general type of the payload
+ typedef Payload* storage_type; // how the payload is actually stored
+ typedef Payload* insert_type; // what parameter is inserted
+
+ typedef Payload* return_type; // what is returned on access
+ typedef const Payload* const_return_type; // what is returned on const access
+
+ typedef BasePayload* base_type; // base type of the entry (when implementation details need to be hidden)
+ typedef const BasePayload* const_base_type; // const base type of the entry (when implementation details need to be hidden)
+
+ static Payload* empty_payload;
+};
+
+template<typename Payload, typename BasePayload>
+Payload*
+pointer_payload_traits<Payload, BasePayload>::empty_payload = NULL;
+
+} // trie
+} // ndn
+
+#endif // NDN_TRIE_PAYLOAD_TRAITS_POINTER_H
diff --git a/ndn-cpp/trie/payload-traits/ptr.h b/ndn-cpp/trie/payload-traits/ptr.h
new file mode 100644
index 0000000..3caf020
--- /dev/null
+++ b/ndn-cpp/trie/payload-traits/ptr.h
@@ -0,0 +1,40 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_TRIE_PAYLOAD_TRAITS_PTR_H
+#define NDN_TRIE_PAYLOAD_TRAITS_PTR_H
+
+namespace ndn {
+namespace trie {
+
+template<typename Payload, typename BasePayload = Payload>
+struct ptr_payload_traits
+{
+ typedef Payload payload_type;
+ typedef Ptr<Payload> storage_type;
+ typedef Ptr<Payload> insert_type;
+
+ typedef Ptr<Payload> return_type;
+ typedef Ptr<const Payload> const_return_type;
+
+ typedef Ptr<BasePayload> base_type;
+ typedef Ptr<const BasePayload> const_base_type;
+
+ static Ptr<Payload> empty_payload;
+};
+
+template<typename Payload, typename BasePayload>
+Ptr<Payload>
+ptr_payload_traits<Payload, BasePayload>::empty_payload; // = Ptr<Payload> ();
+
+} // trie
+} // ndn
+
+#endif // NDN_TRIE_PAYLOAD_TRAITS_PTR_H
diff --git a/ndn-cpp/trie/policies/counting-policy.h b/ndn-cpp/trie/policies/counting-policy.h
new file mode 100644
index 0000000..d27f915
--- /dev/null
+++ b/ndn-cpp/trie/policies/counting-policy.h
@@ -0,0 +1,101 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef COUNTING_POLICY_H_
+#define COUNTING_POLICY_H_
+
+#include <boost/intrusive/options.hpp>
+#include <boost/intrusive/list.hpp>
+
+namespace ndn {
+namespace trie {
+
+/**
+ * @brief Traits for policy that just keeps track of number of elements
+ * It's doing a rather expensive job, but just in case it needs to be extended later
+ */
+struct counting_policy_traits
+{
+ /// @brief Name that can be used to identify the policy (e.g., for logging)
+ static std::string GetName () { return "Counting"; }
+
+ struct policy_hook_type : public boost::intrusive::list_member_hook<> {};
+
+ template<class Container>
+ struct container_hook
+ {
+ // could be class/struct implementation
+ typedef boost::intrusive::member_hook< Container,
+ policy_hook_type,
+ &Container::policy_hook_ > type;
+ };
+
+ template<class Base,
+ class Container,
+ class Hook>
+ struct policy
+ {
+ typedef typename boost::intrusive::list< Container, Hook > policy_container;
+
+ // could be just typedef
+ class type : public policy_container
+ {
+ public:
+ typedef Container parent_trie;
+
+ type (Base &base)
+ : base_ (base)
+ {
+ }
+
+ inline void
+ update (typename parent_trie::iterator item)
+ {
+ // do nothing
+ }
+
+ inline bool
+ insert (typename parent_trie::iterator item)
+ {
+ policy_container::push_back (*item);
+ return true;
+ }
+
+ inline void
+ lookup (typename parent_trie::iterator item)
+ {
+ // do nothing
+ }
+
+ inline void
+ erase (typename parent_trie::iterator item)
+ {
+ policy_container::erase (policy_container::s_iterator_to (*item));
+ }
+
+ inline void
+ clear ()
+ {
+ policy_container::clear ();
+ }
+
+ private:
+ type () : base_(*((Base*)0)) { };
+
+ private:
+ Base &base_;
+ };
+ };
+};
+
+} // trie
+} // ndn
+
+#endif // COUNTING_POLICY_H_
diff --git a/ndn-cpp/trie/policies/empty-policy.h b/ndn-cpp/trie/policies/empty-policy.h
new file mode 100644
index 0000000..0cfe962
--- /dev/null
+++ b/ndn-cpp/trie/policies/empty-policy.h
@@ -0,0 +1,50 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef EMPTY_POLICY_H_
+#define EMPTY_POLICY_H_
+
+namespace ndn {
+namespace trie {
+
+/**
+ * @brief Traits for empty (bogus) replacement policy
+ */
+struct empty_policy_traits
+{
+ /// @brief Name that can be used to identify the policy (e.g., for logging)
+ static std::string GetName () { return ""; }
+
+ typedef void* policy_hook_type;
+
+ template<class Container> struct container_hook { typedef void* type; };
+
+ template<class Base,
+ class Container,
+ class Hook>
+ struct policy
+ {
+ struct type
+ {
+ inline type (Base &base) {}
+
+ inline void update (typename Container::iterator) { }
+ inline bool insert (typename Container::iterator) { return true; }
+ inline void lookup (typename Container::iterator item) { }
+ inline void erase (typename Container::iterator item) { }
+ inline void clear () { }
+ };
+ };
+};
+
+} // trie
+} // ndn
+
+#endif // EMPTY_POLICY_H_
diff --git a/ndn-cpp/trie/policies/fifo-policy.h b/ndn-cpp/trie/policies/fifo-policy.h
new file mode 100644
index 0000000..7acad2b
--- /dev/null
+++ b/ndn-cpp/trie/policies/fifo-policy.h
@@ -0,0 +1,119 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef FIFO_POLICY_H_
+#define FIFO_POLICY_H_
+
+#include <boost/intrusive/options.hpp>
+#include <boost/intrusive/list.hpp>
+
+namespace ndn {
+namespace trie {
+
+/**
+ * @brief Traits for First In First Out replacement policy
+ */
+struct fifo_policy_traits
+{
+ /// @brief Name that can be used to identify the policy (e.g., for logging)
+ static std::string GetName () { return "Fifo"; }
+
+ struct policy_hook_type : public boost::intrusive::list_member_hook<> {};
+
+ template<class Container>
+ struct container_hook
+ {
+ // could be class/struct implementation
+ typedef boost::intrusive::member_hook< Container,
+ policy_hook_type,
+ &Container::policy_hook_ > type;
+ };
+
+ template<class Base,
+ class Container,
+ class Hook>
+ struct policy
+ {
+ typedef typename boost::intrusive::list< Container, Hook > policy_container;
+
+ // could be just typedef
+ class type : public policy_container
+ {
+ public:
+ typedef Container parent_trie;
+
+ type (Base &base)
+ : base_ (base)
+ , max_size_ (100)
+ {
+ }
+
+ inline void
+ update (typename parent_trie::iterator item)
+ {
+ // do nothing
+ }
+
+ inline bool
+ insert (typename parent_trie::iterator item)
+ {
+ if (max_size_ != 0 && policy_container::size () >= max_size_)
+ {
+ base_.erase (&(*policy_container::begin ()));
+ }
+
+ policy_container::push_back (*item);
+ return true;
+ }
+
+ inline void
+ lookup (typename parent_trie::iterator item)
+ {
+ // do nothing
+ }
+
+ inline void
+ erase (typename parent_trie::iterator item)
+ {
+ policy_container::erase (policy_container::s_iterator_to (*item));
+ }
+
+ inline void
+ clear ()
+ {
+ policy_container::clear ();
+ }
+
+ inline void
+ set_max_size (size_t max_size)
+ {
+ max_size_ = max_size;
+ }
+
+ inline size_t
+ get_max_size () const
+ {
+ return max_size_;
+ }
+
+ private:
+ type () : base_(*((Base*)0)) { };
+
+ private:
+ Base &base_;
+ size_t max_size_;
+ };
+ };
+};
+
+} // trie
+} // ndn
+
+#endif
diff --git a/ndn-cpp/trie/policies/lfu-policy.h b/ndn-cpp/trie/policies/lfu-policy.h
new file mode 100644
index 0000000..802f64b
--- /dev/null
+++ b/ndn-cpp/trie/policies/lfu-policy.h
@@ -0,0 +1,149 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef LFU_POLICY_H_
+#define LFU_POLICY_H_
+
+#include <boost/intrusive/options.hpp>
+#include <boost/intrusive/set.hpp>
+
+namespace ndn {
+namespace trie {
+
+/**
+ * @brief Traits for LFU replacement policy
+ */
+struct lfu_policy_traits
+{
+ /// @brief Name that can be used to identify the policy (e.g., for logging)
+ static std::string GetName () { return "Lfu"; }
+
+ struct policy_hook_type : public boost::intrusive::set_member_hook<> { double frequency; };
+
+ template<class Container>
+ struct container_hook
+ {
+ typedef boost::intrusive::member_hook< Container,
+ policy_hook_type,
+ &Container::policy_hook_ > type;
+ };
+
+ template<class Base,
+ class Container,
+ class Hook>
+ struct policy
+ {
+ static double& get_order (typename Container::iterator item)
+ {
+ return static_cast<policy_hook_type*>
+ (policy_container::value_traits::to_node_ptr(*item))->frequency;
+ }
+
+ static const double& get_order (typename Container::const_iterator item)
+ {
+ return static_cast<const policy_hook_type*>
+ (policy_container::value_traits::to_node_ptr(*item))->frequency;
+ }
+
+ template<class Key>
+ struct MemberHookLess
+ {
+ bool operator () (const Key &a, const Key &b) const
+ {
+ return get_order (&a) < get_order (&b);
+ }
+ };
+
+ typedef boost::intrusive::multiset< Container,
+ boost::intrusive::compare< MemberHookLess< Container > >,
+ Hook > policy_container;
+
+ // could be just typedef
+ class type : public policy_container
+ {
+ public:
+ typedef policy policy_base; // to get access to get_order methods from outside
+ typedef Container parent_trie;
+
+ type (Base &base)
+ : base_ (base)
+ , max_size_ (100)
+ {
+ }
+
+ inline void
+ update (typename parent_trie::iterator item)
+ {
+ policy_container::erase (policy_container::s_iterator_to (*item));
+ get_order (item) += 1;
+ policy_container::insert (*item);
+ }
+
+ inline bool
+ insert (typename parent_trie::iterator item)
+ {
+ get_order (item) = 0;
+
+ if (max_size_ != 0 && policy_container::size () >= max_size_)
+ {
+ // this erases the "least frequently used item" from cache
+ base_.erase (&(*policy_container::begin ()));
+ }
+
+ policy_container::insert (*item);
+ return true;
+ }
+
+ inline void
+ lookup (typename parent_trie::iterator item)
+ {
+ policy_container::erase (policy_container::s_iterator_to (*item));
+ get_order (item) += 1;
+ policy_container::insert (*item);
+ }
+
+ inline void
+ erase (typename parent_trie::iterator item)
+ {
+ policy_container::erase (policy_container::s_iterator_to (*item));
+ }
+
+ inline void
+ clear ()
+ {
+ policy_container::clear ();
+ }
+
+ inline void
+ set_max_size (size_t max_size)
+ {
+ max_size_ = max_size;
+ }
+
+ inline size_t
+ get_max_size () const
+ {
+ return max_size_;
+ }
+
+ private:
+ type () : base_(*((Base*)0)) { };
+
+ private:
+ Base &base_;
+ size_t max_size_;
+ };
+ };
+};
+
+} // trie
+} // ndn
+
+#endif // LFU_POLICY_H
diff --git a/ndn-cpp/trie/policies/lru-policy.h b/ndn-cpp/trie/policies/lru-policy.h
new file mode 100644
index 0000000..ad3a382
--- /dev/null
+++ b/ndn-cpp/trie/policies/lru-policy.h
@@ -0,0 +1,124 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef LRU_POLICY_H_
+#define LRU_POLICY_H_
+
+#include <boost/intrusive/options.hpp>
+#include <boost/intrusive/list.hpp>
+
+namespace ndn {
+namespace trie {
+
+/**
+ * @brief Traits for Least Recently Used replacement policy
+ */
+struct lru_policy_traits
+{
+ /// @brief Name that can be used to identify the policy (e.g., for logging)
+ static std::string GetName () { return "Lru"; }
+
+ struct policy_hook_type : public boost::intrusive::list_member_hook<> {};
+
+ template<class Container>
+ struct container_hook
+ {
+ typedef boost::intrusive::member_hook< Container,
+ policy_hook_type,
+ &Container::policy_hook_ > type;
+ };
+
+ template<class Base,
+ class Container,
+ class Hook>
+ struct policy
+ {
+ typedef typename boost::intrusive::list< Container, Hook > policy_container;
+
+ // could be just typedef
+ class type : public policy_container
+ {
+ public:
+ typedef Container parent_trie;
+
+ type (Base &base)
+ : base_ (base)
+ , max_size_ (100)
+ {
+ }
+
+ inline void
+ update (typename parent_trie::iterator item)
+ {
+ // do relocation
+ policy_container::splice (policy_container::end (),
+ *this,
+ policy_container::s_iterator_to (*item));
+ }
+
+ inline bool
+ insert (typename parent_trie::iterator item)
+ {
+ if (max_size_ != 0 && policy_container::size () >= max_size_)
+ {
+ base_.erase (&(*policy_container::begin ()));
+ }
+
+ policy_container::push_back (*item);
+ return true;
+ }
+
+ inline void
+ lookup (typename parent_trie::iterator item)
+ {
+ // do relocation
+ policy_container::splice (policy_container::end (),
+ *this,
+ policy_container::s_iterator_to (*item));
+ }
+
+ inline void
+ erase (typename parent_trie::iterator item)
+ {
+ policy_container::erase (policy_container::s_iterator_to (*item));
+ }
+
+ inline void
+ clear ()
+ {
+ policy_container::clear ();
+ }
+
+ inline void
+ set_max_size (size_t max_size)
+ {
+ max_size_ = max_size;
+ }
+
+ inline size_t
+ get_max_size () const
+ {
+ return max_size_;
+ }
+
+ private:
+ type () : base_(*((Base*)0)) { };
+
+ private:
+ Base &base_;
+ size_t max_size_;
+ };
+ };
+};
+
+} // trie
+} // ndn
+
+#endif
diff --git a/ndn-cpp/trie/policies/multi-policy.h b/ndn-cpp/trie/policies/multi-policy.h
new file mode 100644
index 0000000..739de7b
--- /dev/null
+++ b/ndn-cpp/trie/policies/multi-policy.h
@@ -0,0 +1,177 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef MULTI_POLICY_H_
+#define MULTI_POLICY_H_
+
+#include "detail/multi-type-container.h"
+#include "detail/multi-policy-container.h"
+#include "detail/functor-hook.h"
+
+#include <boost/mpl/size.hpp>
+#include <boost/mpl/at.hpp>
+#include <boost/mpl/range_c.hpp>
+#include <boost/mpl/transform.hpp>
+#include <boost/mpl/back_inserter.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/mpl/for_each.hpp>
+
+#include <boost/intrusive/options.hpp>
+
+namespace ndn {
+namespace trie {
+
+template<typename Policies> // e.g., mpl::vector1< lru_policy_traits >
+struct multi_policy_traits
+{
+ typedef Policies policy_traits;
+
+ struct getHook { template<class Item> struct apply { typedef typename Item::policy_hook_type type; }; };
+ typedef detail::multi_type_container< typename boost::mpl::transform1<policy_traits, getHook>::type > policy_hook_type;
+
+ template<class Container>
+ struct container_hook
+ {
+ typedef policy_hook_type type;
+ };
+
+ template<class Base,
+ class Container,
+ class Hook>
+ struct policy
+ {
+ typedef boost::mpl::range_c<int, 0, boost::mpl::size<policy_traits>::type::value> policies_range;
+
+ struct getPolicy
+ {
+ template<class Number>
+ struct apply
+ {
+ typedef
+ typename boost::mpl::at_c<policy_traits, Number::value>::type::
+ template policy<Base,
+ Container,
+ boost::intrusive::function_hook< detail::FunctorHook <Hook,
+ Container,
+ Number::value> > >::type
+ type;
+ };
+ };
+
+ typedef
+ typename boost::mpl::transform1<policies_range,
+ getPolicy,
+ boost::mpl::back_inserter< boost::mpl::vector0<> > >::type policies;
+
+
+ typedef detail::multi_policy_container< Base, policies > policy_container;
+
+ class type : public policy_container
+ {
+ public:
+ typedef policy policy_base; // to get access to get_time methods from outside
+ typedef Container parent_trie;
+
+ type (Base &base)
+ : policy_container (base)
+ {
+ }
+
+ inline void
+ update (typename parent_trie::iterator item)
+ {
+ policy_container::update (item);
+ }
+
+ inline bool
+ insert (typename parent_trie::iterator item)
+ {
+ return policy_container::insert (item);
+ }
+
+ inline void
+ lookup (typename parent_trie::iterator item)
+ {
+ policy_container::lookup (item);
+ }
+
+ inline void
+ erase (typename parent_trie::iterator item)
+ {
+ policy_container::erase (item);
+ }
+
+ inline void
+ clear ()
+ {
+ policy_container::clear ();
+ }
+
+ struct max_size_setter
+ {
+ max_size_setter (policy_container &container, size_t size) : m_container (container), m_size (size) { }
+
+ template< typename U > void operator() (U index)
+ {
+ m_container.template get<U::value> ().set_max_size (m_size);
+ }
+
+ private:
+ policy_container &m_container;
+ size_t m_size;
+ };
+
+ inline void
+ set_max_size (size_t max_size)
+ {
+ boost::mpl::for_each< boost::mpl::range_c<int, 0, boost::mpl::size<policy_traits>::type::value> >
+ (max_size_setter (*this, max_size));
+ }
+
+ inline size_t
+ get_max_size () const
+ {
+ // as max size should be the same everywhere, get the value from the first available policy
+ return policy_container::template get<0> ().get_max_size ();
+ }
+
+ };
+ };
+
+
+ struct name_getter
+ {
+ name_getter (std::string &name) : m_name (name) { }
+
+ template< typename U > void operator() (U index)
+ {
+ if (!m_name.empty ())
+ m_name += "::";
+ m_name += boost::mpl::at_c< policy_traits, U::value >::type::GetName ();
+ }
+
+ std::string &m_name;
+ };
+
+ /// @brief Name that can be used to identify the policy (e.g., for logging)
+ static std::string GetName ()
+ {
+ // combine names of all internal policies
+ std::string name;
+ boost::mpl::for_each< boost::mpl::range_c<int, 0, boost::mpl::size<policy_traits>::type::value> > (name_getter (name));
+
+ return name;
+ }
+};
+
+} // trie
+} // ndn
+
+#endif // MULTI_POLICY_H_
diff --git a/ndn-cpp/trie/policies/persistent-policy.h b/ndn-cpp/trie/policies/persistent-policy.h
new file mode 100644
index 0000000..d34f373
--- /dev/null
+++ b/ndn-cpp/trie/policies/persistent-policy.h
@@ -0,0 +1,119 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef PERSISTENT_POLICY_H_
+#define PERSISTENT_POLICY_H_
+
+#include <boost/intrusive/options.hpp>
+#include <boost/intrusive/list.hpp>
+
+namespace ndn {
+namespace trie {
+
+/**
+ * @brief Traits for persistent replacement policy
+ *
+ * In this policy entries are added until there is a space (controlled by set_max_size call).
+ * If maximum is reached, new entries will not be added and nothing will be removed from the container
+ */
+struct persistent_policy_traits
+{
+ /// @brief Name that can be used to identify the policy (e.g., for logging)
+ static std::string GetName () { return "Persistent"; }
+
+ struct policy_hook_type : public boost::intrusive::list_member_hook<> {};
+
+ template<class Container>
+ struct container_hook
+ {
+ typedef boost::intrusive::member_hook< Container,
+ policy_hook_type,
+ &Container::policy_hook_ > type;
+ };
+
+ template<class Base,
+ class Container,
+ class Hook>
+ struct policy
+ {
+ typedef typename boost::intrusive::list< Container, Hook > policy_container;
+
+ // could be just typedef
+ class type : public policy_container
+ {
+ public:
+ typedef Container parent_trie;
+
+ type (Base &base)
+ : base_ (base)
+ , max_size_ (100) // when 0, policy is not enforced
+ {
+ }
+
+ inline void
+ update (typename parent_trie::iterator item)
+ {
+ // do nothing
+ }
+
+ inline bool
+ insert (typename parent_trie::iterator item)
+ {
+ if (max_size_ != 0 && policy_container::size () >= max_size_)
+ return false;
+
+ policy_container::push_back (*item);
+ return true;
+ }
+
+ inline void
+ lookup (typename parent_trie::iterator item)
+ {
+ // do nothing
+ }
+
+ inline void
+ erase (typename parent_trie::iterator item)
+ {
+ policy_container::erase (policy_container::s_iterator_to (*item));
+ }
+
+ inline void
+ clear ()
+ {
+ policy_container::clear ();
+ }
+
+ inline void
+ set_max_size (size_t max_size)
+ {
+ max_size_ = max_size;
+ }
+
+ inline size_t
+ get_max_size () const
+ {
+ return max_size_;
+ }
+
+ private:
+ // type () : base_(*((Base*)0)) { };
+
+ private:
+ Base &base_;
+ size_t max_size_;
+ };
+ };
+};
+
+} // trie
+} // ndn
+
+#endif // PERSISTENT_POLICY_H_
diff --git a/ndn-cpp/trie/policies/random-policy.h b/ndn-cpp/trie/policies/random-policy.h
new file mode 100644
index 0000000..d896e89
--- /dev/null
+++ b/ndn-cpp/trie/policies/random-policy.h
@@ -0,0 +1,158 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef RANDOM_POLICY_H_
+#define RANDOM_POLICY_H_
+
+#include "ns3/random-variable.h"
+
+#include <boost/intrusive/options.hpp>
+#include <boost/intrusive/set.hpp>
+
+namespace ndn {
+namespace trie {
+
+/**
+ * @brief Traits for random replacement policy
+ */
+struct random_policy_traits
+{
+ /// @brief Name that can be used to identify the policy (e.g., for logging)
+ static std::string GetName () { return "Random"; }
+
+ struct policy_hook_type : public boost::intrusive::set_member_hook<> { uint32_t randomOrder; };
+
+ template<class Container>
+ struct container_hook
+ {
+ typedef boost::intrusive::member_hook< Container,
+ policy_hook_type,
+ &Container::policy_hook_ > type;
+ };
+
+ template<class Base,
+ class Container,
+ class Hook>
+ struct policy
+ {
+ static uint32_t& get_order (typename Container::iterator item)
+ {
+ return static_cast<typename policy_container::value_traits::hook_type*>
+ (policy_container::value_traits::to_node_ptr(*item))->randomOrder;
+ }
+
+ static const uint32_t& get_order (typename Container::const_iterator item)
+ {
+ return static_cast<const typename policy_container::value_traits::hook_type*>
+ (policy_container::value_traits::to_node_ptr(*item))->randomOrder;
+ }
+
+ template<class Key>
+ struct MemberHookLess
+ {
+ bool operator () (const Key &a, const Key &b) const
+ {
+ return get_order (&a) < get_order (&b);
+ }
+ };
+
+ typedef boost::intrusive::multiset< Container,
+ boost::intrusive::compare< MemberHookLess< Container > >,
+ Hook > policy_container;
+
+ // could be just typedef
+ class type : public policy_container
+ {
+ public:
+ typedef policy policy_base; // to get access to get_order methods from outside
+ typedef Container parent_trie;
+
+ type (Base &base)
+ : base_ (base)
+ , u_rand (0, std::numeric_limits<uint32_t>::max ())
+ , max_size_ (100)
+ {
+ }
+
+ inline void
+ update (typename parent_trie::iterator item)
+ {
+ // do nothing. it's random policy
+ }
+
+ inline bool
+ insert (typename parent_trie::iterator item)
+ {
+ get_order (item) = u_rand.GetValue ();
+
+ if (max_size_ != 0 && policy_container::size () >= max_size_)
+ {
+ if (MemberHookLess<Container>() (*item, *policy_container::begin ()))
+ {
+ // std::cout << "Cannot add. Signaling fail\n";
+ // just return false. Indicating that insert "failed"
+ return false;
+ }
+ else
+ {
+ // removing some random element
+ base_.erase (&(*policy_container::begin ()));
+ }
+ }
+
+ policy_container::insert (*item);
+ return true;
+ }
+
+ inline void
+ lookup (typename parent_trie::iterator item)
+ {
+ // do nothing. it's random policy
+ }
+
+ inline void
+ erase (typename parent_trie::iterator item)
+ {
+ policy_container::erase (policy_container::s_iterator_to (*item));
+ }
+
+ inline void
+ clear ()
+ {
+ policy_container::clear ();
+ }
+
+ inline void
+ set_max_size (size_t max_size)
+ {
+ max_size_ = max_size;
+ }
+
+ inline size_t
+ get_max_size () const
+ {
+ return max_size_;
+ }
+
+ private:
+ type () : base_(*((Base*)0)) { };
+
+ private:
+ Base &base_;
+ ns3::UniformVariable u_rand;
+ size_t max_size_;
+ };
+ };
+};
+
+} // trie
+} // ndn
+
+#endif // RANDOM_POLICY_H
diff --git a/ndn-cpp/trie/trie-with-policy.h b/ndn-cpp/trie/trie-with-policy.h
new file mode 100644
index 0000000..5a0d896
--- /dev/null
+++ b/ndn-cpp/trie/trie-with-policy.h
@@ -0,0 +1,263 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef TRIE_TRIE_WITH_POLICY_H_
+#define TRIE_TRIE_WITH_POLICY_H_
+
+#include "trie.h"
+
+namespace ndn {
+namespace trie {
+
+template<typename FullKey,
+ typename PayloadTraits,
+ typename PolicyTraits
+ >
+class trie_with_policy
+{
+public:
+ typedef trie< FullKey,
+ PayloadTraits,
+ typename PolicyTraits::policy_hook_type > parent_trie;
+
+ typedef typename parent_trie::iterator iterator;
+ typedef typename parent_trie::const_iterator const_iterator;
+ typedef typename parent_trie::payload_traits payload_traits;
+
+ typedef typename PolicyTraits::template policy<
+ trie_with_policy<FullKey, PayloadTraits, PolicyTraits>,
+ parent_trie,
+ typename PolicyTraits::template container_hook<parent_trie>::type >::type policy_container;
+
+ inline
+ trie_with_policy (size_t bucketSize = 10, size_t bucketIncrement = 10)
+ : trie_ ("", bucketSize, bucketIncrement)
+ , policy_ (*this)
+ {
+ }
+
+ inline std::pair< iterator, bool >
+ insert (const FullKey &key, typename PayloadTraits::insert_type payload)
+ {
+ std::pair<iterator, bool> item =
+ trie_.insert (key, payload);
+
+ if (item.second) // real insert
+ {
+ bool ok = policy_.insert (s_iterator_to (item.first));
+ if (!ok)
+ {
+ item.first->erase (); // cannot insert
+ return std::make_pair (end (), false);
+ }
+ }
+ else
+ {
+ return std::make_pair (s_iterator_to (item.first), false);
+ }
+
+ return item;
+ }
+
+ inline void
+ erase (const FullKey &key)
+ {
+ iterator foundItem, lastItem;
+ bool reachLast;
+ boost::tie (foundItem, reachLast, lastItem) = trie_.find (key);
+
+ if (!reachLast || lastItem->payload () == PayloadTraits::empty_payload)
+ return; // nothing to invalidate
+
+ erase (lastItem);
+ }
+
+ inline void
+ erase (iterator node)
+ {
+ if (node == end ()) return;
+
+ policy_.erase (s_iterator_to (node));
+ node->erase (); // will do cleanup here
+ }
+
+ inline void
+ clear ()
+ {
+ policy_.clear ();
+ trie_.clear ();
+ }
+
+ template<typename Modifier>
+ bool
+ modify (iterator position, Modifier mod)
+ {
+ if (position == end ()) return false;
+ if (position->payload () == PayloadTraits::empty_payload) return false;
+
+ mod (*position->payload ());
+ policy_.update (position);
+ return true;
+ }
+
+ /**
+ * @brief Find a node that has the exact match with the key
+ */
+ inline iterator
+ find_exact (const FullKey &key)
+ {
+ iterator foundItem, lastItem;
+ bool reachLast;
+ boost::tie (foundItem, reachLast, lastItem) = trie_.find (key);
+
+ if (!reachLast || lastItem->payload () == PayloadTraits::empty_payload)
+ return end ();
+
+ return lastItem;
+ }
+
+ /**
+ * @brief Find a node that has the longest common prefix with key (FIB/PIT lookup)
+ */
+ inline iterator
+ longest_prefix_match (const FullKey &key)
+ {
+ iterator foundItem, lastItem;
+ bool reachLast;
+ boost::tie (foundItem, reachLast, lastItem) = trie_.find (key);
+ if (foundItem != trie_.end ())
+ {
+ policy_.lookup (s_iterator_to (foundItem));
+ }
+ return foundItem;
+ }
+
+ /**
+ * @brief Find a node that has the longest common prefix with key (FIB/PIT lookup)
+ */
+ template<class Predicate>
+ inline iterator
+ longest_prefix_match_if (const FullKey &key, Predicate pred)
+ {
+ iterator foundItem, lastItem;
+ bool reachLast;
+ boost::tie (foundItem, reachLast, lastItem) = trie_.find_if (key, pred);
+ if (foundItem != trie_.end ())
+ {
+ policy_.lookup (s_iterator_to (foundItem));
+ }
+ return foundItem;
+ }
+
+ // /**
+ // * @brief Const version of the longest common prefix match
+ // * (semi-const, because there could be update of the policy anyways)
+ // */
+ // inline const_iterator
+ // longest_prefix_match (const FullKey &key) const
+ // {
+ // return static_cast<trie_with_policy*> (this)->longest_prefix_match (key);
+ // }
+
+ /**
+ * @brief Find a node that has prefix at least as the key (cache lookup)
+ */
+ inline iterator
+ deepest_prefix_match (const FullKey &key)
+ {
+ iterator foundItem, lastItem;
+ bool reachLast;
+ boost::tie (foundItem, reachLast, lastItem) = trie_.find (key);
+
+ // guard in case we don't have anything in the trie
+ if (lastItem == trie_.end ())
+ return trie_.end ();
+
+ if (reachLast)
+ {
+ if (foundItem == trie_.end ())
+ {
+ foundItem = lastItem->find (); // should be something
+ }
+ policy_.lookup (s_iterator_to (foundItem));
+ return foundItem;
+ }
+ else
+ { // couldn't find a node that has prefix at least as key
+ return trie_.end ();
+ }
+ }
+
+ /**
+ * @brief Find a node that has prefix at least as the key
+ */
+ template<class Predicate>
+ inline iterator
+ deepest_prefix_match (const FullKey &key, Predicate pred)
+ {
+ iterator foundItem, lastItem;
+ bool reachLast;
+ boost::tie (foundItem, reachLast, lastItem) = trie_.find (key);
+
+ // guard in case we don't have anything in the trie
+ if (lastItem == trie_.end ())
+ return trie_.end ();
+
+ if (reachLast)
+ {
+ foundItem = lastItem->find_if (pred); // may or may not find something
+ if (foundItem == trie_.end ())
+ {
+ return trie_.end ();
+ }
+ policy_.lookup (s_iterator_to (foundItem));
+ return foundItem;
+ }
+ else
+ { // couldn't find a node that has prefix at least as key
+ return trie_.end ();
+ }
+ }
+
+ iterator end () const
+ {
+ return 0;
+ }
+
+ const parent_trie &
+ getTrie () const { return trie_; }
+
+ parent_trie &
+ getTrie () { return trie_; }
+
+ const policy_container &
+ getPolicy () const { return policy_; }
+
+ policy_container &
+ getPolicy () { return policy_; }
+
+ static inline iterator
+ s_iterator_to (typename parent_trie::iterator item)
+ {
+ if (item == 0)
+ return 0;
+ else
+ return &(*item);
+ }
+
+private:
+ parent_trie trie_;
+ mutable policy_container policy_;
+};
+
+} // trie
+} // ndn
+
+#endif // TRIE_TRIE_WITH_POLICY_H_
diff --git a/ndn-cpp/trie/trie.h b/ndn-cpp/trie/trie.h
new file mode 100644
index 0000000..edc8a1b
--- /dev/null
+++ b/ndn-cpp/trie/trie.h
@@ -0,0 +1,636 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_TRIE_TRIE_H_
+#define NDN_TRIE_TRIE_H_
+
+#include <boost/intrusive/unordered_set.hpp>
+#include <boost/intrusive/list.hpp>
+#include <boost/intrusive/set.hpp>
+#include <boost/functional/hash.hpp>
+#include <boost/interprocess/smart_ptr/unique_ptr.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/foreach.hpp>
+#include <boost/mpl/if.hpp>
+
+#include "payload-traits/pointer.h"
+#include "payload-traits/ptr.h"
+
+namespace ndn {
+namespace trie {
+
+////////////////////////////////////////////////////
+// forward declarations
+//
+template<typename FullKey,
+ typename PayloadTraits,
+ typename PolicyHook >
+class trie;
+
+template<typename FullKey, typename PayloadTraits, typename PolicyHook>
+inline std::ostream&
+operator << (std::ostream &os,
+ const trie<FullKey, PayloadTraits, PolicyHook> &trie_node);
+
+template<typename FullKey, typename PayloadTraits, typename PolicyHook>
+bool
+operator== (const trie<FullKey, PayloadTraits, PolicyHook> &a,
+ const trie<FullKey, PayloadTraits, PolicyHook> &b);
+
+template<typename FullKey, typename PayloadTraits, typename PolicyHook >
+std::size_t
+hash_value (const trie<FullKey, PayloadTraits, PolicyHook> &trie_node);
+
+///////////////////////////////////////////////////
+// actual definition
+//
+template<class T, class NonConstT>
+class trie_iterator;
+
+template<class T>
+class trie_point_iterator;
+
+template<typename FullKey,
+ typename PayloadTraits,
+ typename PolicyHook >
+class trie
+{
+public:
+ typedef typename FullKey::partial_type Key;
+
+ typedef trie* iterator;
+ typedef const trie* const_iterator;
+
+ typedef trie_iterator<trie, trie> recursive_iterator;
+ typedef trie_iterator<const trie, trie> const_recursive_iterator;
+
+ typedef trie_point_iterator<trie> point_iterator;
+ typedef trie_point_iterator<const trie> const_point_iterator;
+
+ typedef PayloadTraits payload_traits;
+
+ inline
+ trie (const Key &key, size_t bucketSize = 10, size_t bucketIncrement = 10)
+ : key_ (key)
+ , initialBucketSize_ (bucketSize)
+ , bucketIncrement_ (bucketIncrement)
+ , bucketSize_ (initialBucketSize_)
+ , buckets_ (new bucket_type [bucketSize_]) //cannot use normal pointer, because lifetime of buckets should be larger than lifetime of the container
+ , children_ (bucket_traits (buckets_.get (), bucketSize_))
+ , payload_ (PayloadTraits::empty_payload)
+ , parent_ (0)
+ {
+ }
+
+ inline
+ ~trie ()
+ {
+ payload_ = PayloadTraits::empty_payload; // necessary for smart pointers...
+ children_.clear_and_dispose (trie_delete_disposer ());
+ }
+
+ void
+ clear ()
+ {
+ children_.clear_and_dispose (trie_delete_disposer ());
+ }
+
+ template<class Predicate>
+ void
+ clear_if (Predicate cond)
+ {
+ recursive_iterator trieNode (this);
+ recursive_iterator end (0);
+
+ while (trieNode != end)
+ {
+ if (cond (*trieNode))
+ {
+ trieNode = recursive_iterator (trieNode->erase ());
+ }
+ trieNode ++;
+ }
+ }
+
+ // actual entry
+ friend bool
+ operator== <> (const trie<FullKey, PayloadTraits, PolicyHook> &a,
+ const trie<FullKey, PayloadTraits, PolicyHook> &b);
+
+ friend std::size_t
+ hash_value <> (const trie<FullKey, PayloadTraits, PolicyHook> &trie_node);
+
+ inline std::pair<iterator, bool>
+ insert (const FullKey &key,
+ typename PayloadTraits::insert_type payload)
+ {
+ trie *trieNode = this;
+
+ BOOST_FOREACH (const Key &subkey, key)
+ {
+ typename unordered_set::iterator item = trieNode->children_.find (subkey);
+ if (item == trieNode->children_.end ())
+ {
+ trie *newNode = new trie (subkey, initialBucketSize_, bucketIncrement_);
+ // std::cout << "new " << newNode << "\n";
+ newNode->parent_ = trieNode;
+
+ if (trieNode->children_.size () >= trieNode->bucketSize_)
+ {
+ trieNode->bucketSize_ += trieNode->bucketIncrement_;
+ trieNode->bucketIncrement_ *= 2; // increase bucketIncrement exponentially
+
+ buckets_array newBuckets (new bucket_type [trieNode->bucketSize_]);
+ trieNode->children_.rehash (bucket_traits (newBuckets.get (), trieNode->bucketSize_));
+ trieNode->buckets_.swap (newBuckets);
+ }
+
+ std::pair< typename unordered_set::iterator, bool > ret =
+ trieNode->children_.insert (*newNode);
+
+ trieNode = &(*ret.first);
+ }
+ else
+ trieNode = &(*item);
+ }
+
+ if (trieNode->payload_ == PayloadTraits::empty_payload)
+ {
+ trieNode->payload_ = payload;
+ return std::make_pair (trieNode, true);
+ }
+ else
+ return std::make_pair (trieNode, false);
+ }
+
+ /**
+ * @brief Removes payload (if it exists) and if there are no children, prunes parents trie
+ */
+ inline iterator
+ erase ()
+ {
+ payload_ = PayloadTraits::empty_payload;
+ return prune ();
+ }
+
+ /**
+ * @brief Do exactly as erase, but without erasing the payload
+ */
+ inline iterator
+ prune ()
+ {
+ if (payload_ == PayloadTraits::empty_payload &&
+ children_.size () == 0)
+ {
+ if (parent_ == 0) return this;
+
+ trie *parent = parent_;
+ parent->children_.erase_and_dispose (*this, trie_delete_disposer ()); // delete this; basically, committing a suicide
+
+ return parent->prune ();
+ }
+ return this;
+ }
+
+ /**
+ * @brief Perform prune of the node, but without attempting to parent of the node
+ */
+ inline void
+ prune_node ()
+ {
+ if (payload_ == PayloadTraits::empty_payload &&
+ children_.size () == 0)
+ {
+ if (parent_ == 0) return;
+
+ trie *parent = parent_;
+ parent->children_.erase_and_dispose (*this, trie_delete_disposer ()); // delete this; basically, committing a suicide
+ }
+ }
+
+ // inline boost::tuple<const iterator, bool, const iterator>
+ // find (const FullKey &key) const
+ // {
+ // return const_cast<trie*> (this)->find (key);
+ // }
+
+ /**
+ * @brief Perform the longest prefix match
+ * @param key the key for which to perform the longest prefix match
+ *
+ * @return ->second is true if prefix in ->first is longer than key
+ */
+ inline boost::tuple<iterator, bool, iterator>
+ find (const FullKey &key)
+ {
+ trie *trieNode = this;
+ iterator foundNode = (payload_ != PayloadTraits::empty_payload) ? this : 0;
+ bool reachLast = true;
+
+ BOOST_FOREACH (const Key &subkey, key)
+ {
+ typename unordered_set::iterator item = trieNode->children_.find (subkey);
+ if (item == trieNode->children_.end ())
+ {
+ reachLast = false;
+ break;
+ }
+ else
+ {
+ trieNode = &(*item);
+
+ if (trieNode->payload_ != PayloadTraits::empty_payload)
+ foundNode = trieNode;
+ }
+ }
+
+ return boost::make_tuple (foundNode, reachLast, trieNode);
+ }
+
+ /**
+ * @brief Perform the longest prefix match satisfying preficate
+ * @param key the key for which to perform the longest prefix match
+ *
+ * @return ->second is true if prefix in ->first is longer than key
+ */
+ template<class Predicate>
+ inline boost::tuple<iterator, bool, iterator>
+ find_if (const FullKey &key, Predicate pred)
+ {
+ trie *trieNode = this;
+ iterator foundNode = (payload_ != PayloadTraits::empty_payload) ? this : 0;
+ bool reachLast = true;
+
+ BOOST_FOREACH (const Key &subkey, key)
+ {
+ typename unordered_set::iterator item = trieNode->children_.find (subkey);
+ if (item == trieNode->children_.end ())
+ {
+ reachLast = false;
+ break;
+ }
+ else
+ {
+ trieNode = &(*item);
+
+ if (trieNode->payload_ != PayloadTraits::empty_payload &&
+ pred (trieNode->payload_))
+ {
+ foundNode = trieNode;
+ }
+ }
+ }
+
+ return boost::make_tuple (foundNode, reachLast, trieNode);
+ }
+
+ /**
+ * @brief Find next payload of the sub-trie
+ * @returns end() or a valid iterator pointing to the trie leaf (order is not defined, enumeration )
+ */
+ inline iterator
+ find ()
+ {
+ if (payload_ != PayloadTraits::empty_payload)
+ return this;
+
+ typedef trie<FullKey, PayloadTraits, PolicyHook> trie;
+ for (typename trie::unordered_set::iterator subnode = children_.begin ();
+ subnode != children_.end ();
+ subnode++ )
+ // BOOST_FOREACH (trie &subnode, children_)
+ {
+ iterator value = subnode->find ();
+ if (value != 0)
+ return value;
+ }
+
+ return 0;
+ }
+
+ /**
+ * @brief Find next payload of the sub-trie satisfying the predicate
+ * @param pred predicate
+ * @returns end() or a valid iterator pointing to the trie leaf (order is not defined, enumeration )
+ */
+ template<class Predicate>
+ inline const iterator
+ find_if (Predicate pred)
+ {
+ if (payload_ != PayloadTraits::empty_payload && pred (payload_))
+ return this;
+
+ typedef trie<FullKey, PayloadTraits, PolicyHook> trie;
+ for (typename trie::unordered_set::iterator subnode = children_.begin ();
+ subnode != children_.end ();
+ subnode++ )
+ // BOOST_FOREACH (const trie &subnode, children_)
+ {
+ iterator value = subnode->find_if (pred);
+ if (value != 0)
+ return value;
+ }
+
+ return 0;
+ }
+
+ iterator end ()
+ {
+ return 0;
+ }
+
+ const_iterator end () const
+ {
+ return 0;
+ }
+
+ typename PayloadTraits::const_return_type
+ payload () const
+ {
+ return payload_;
+ }
+
+ typename PayloadTraits::return_type
+ payload ()
+ {
+ return payload_;
+ }
+
+ void
+ set_payload (typename PayloadTraits::insert_type payload)
+ {
+ payload_ = payload;
+ }
+
+ Key key () const
+ {
+ return key_;
+ }
+
+ inline void
+ PrintStat (std::ostream &os) const;
+
+private:
+ //The disposer object function
+ struct trie_delete_disposer
+ {
+ void operator() (trie *delete_this)
+ {
+ delete delete_this;
+ }
+ };
+
+ template<class D>
+ struct array_disposer
+ {
+ void operator() (D *array)
+ {
+ delete [] array;
+ }
+ };
+
+ friend
+ std::ostream&
+ operator<< < > (std::ostream &os, const trie &trie_node);
+
+public:
+ PolicyHook policy_hook_;
+
+private:
+ boost::intrusive::unordered_set_member_hook<> unordered_set_member_hook_;
+
+ // necessary typedefs
+ typedef trie self_type;
+ typedef boost::intrusive::member_hook< trie,
+ boost::intrusive::unordered_set_member_hook< >,
+ &trie::unordered_set_member_hook_ > member_hook;
+
+ typedef boost::intrusive::unordered_set< trie, member_hook > unordered_set;
+ typedef typename unordered_set::bucket_type bucket_type;
+ typedef typename unordered_set::bucket_traits bucket_traits;
+
+ template<class T, class NonConstT>
+ friend class trie_iterator;
+
+ template<class T>
+ friend class trie_point_iterator;
+
+ ////////////////////////////////////////////////
+ // Actual data
+ ////////////////////////////////////////////////
+
+ Key key_; ///< name component
+
+ size_t initialBucketSize_;
+ size_t bucketIncrement_;
+
+ size_t bucketSize_;
+ typedef boost::interprocess::unique_ptr< bucket_type, array_disposer<bucket_type> > buckets_array;
+ buckets_array buckets_;
+ unordered_set children_;
+
+ typename PayloadTraits::storage_type payload_;
+ trie *parent_; // to make cleaning effective
+};
+
+
+
+
+template<typename FullKey, typename PayloadTraits, typename PolicyHook>
+inline std::ostream&
+operator << (std::ostream &os, const trie<FullKey, PayloadTraits, PolicyHook> &trie_node)
+{
+ os << "# " << trie_node.key_ << ((trie_node.payload_ != PayloadTraits::empty_payload)?"*":"") << std::endl;
+ typedef trie<FullKey, PayloadTraits, PolicyHook> trie;
+
+ for (typename trie::unordered_set::const_iterator subnode = trie_node.children_.begin ();
+ subnode != trie_node.children_.end ();
+ subnode++ )
+ // BOOST_FOREACH (const trie &subnode, trie_node.children_)
+ {
+ os << "\"" << &trie_node << "\"" << " [label=\"" << trie_node.key_ << ((trie_node.payload_ != PayloadTraits::empty_payload)?"*":"") << "\"]\n";
+ os << "\"" << &(*subnode) << "\"" << " [label=\"" << subnode->key_ << ((subnode->payload_ != PayloadTraits::empty_payload)?"*":"") << "\"]""\n";
+
+ os << "\"" << &trie_node << "\"" << " -> " << "\"" << &(*subnode) << "\"" << "\n";
+ os << *subnode;
+ }
+
+ return os;
+}
+
+template<typename FullKey, typename PayloadTraits, typename PolicyHook>
+inline void
+trie<FullKey, PayloadTraits, PolicyHook>
+::PrintStat (std::ostream &os) const
+{
+ os << "# " << key_ << ((payload_ != PayloadTraits::empty_payload)?"*":"") << ": " << children_.size() << " children" << std::endl;
+ for (size_t bucket = 0, maxbucket = children_.bucket_count ();
+ bucket < maxbucket;
+ bucket++)
+ {
+ os << " " << children_.bucket_size (bucket);
+ }
+ os << "\n";
+
+ typedef trie<FullKey, PayloadTraits, PolicyHook> trie;
+ for (typename trie::unordered_set::const_iterator subnode = children_.begin ();
+ subnode != children_.end ();
+ subnode++ )
+ // BOOST_FOREACH (const trie &subnode, children_)
+ {
+ subnode->PrintStat (os);
+ }
+}
+
+
+template<typename FullKey, typename PayloadTraits, typename PolicyHook>
+inline bool
+operator == (const trie<FullKey, PayloadTraits, PolicyHook> &a,
+ const trie<FullKey, PayloadTraits, PolicyHook> &b)
+{
+ return a.key_ == b.key_;
+}
+
+template<typename FullKey, typename PayloadTraits, typename PolicyHook>
+inline std::size_t
+hash_value (const trie<FullKey, PayloadTraits, PolicyHook> &trie_node)
+{
+ return boost::hash_value (trie_node.key_);
+}
+
+
+
+template<class Trie, class NonConstTrie> // hack for boost < 1.47
+class trie_iterator
+{
+public:
+ trie_iterator () : trie_ (0) {}
+ trie_iterator (typename Trie::iterator item) : trie_ (item) {}
+ trie_iterator (Trie &item) : trie_ (&item) {}
+
+ Trie & operator* () { return *trie_; }
+ const Trie & operator* () const { return *trie_; }
+ Trie * operator-> () { return trie_; }
+ const Trie * operator-> () const { return trie_; }
+ bool operator== (trie_iterator<const Trie, NonConstTrie> &other) const { return (trie_ == other.trie_); }
+ bool operator== (trie_iterator<Trie, NonConstTrie> &other) { return (trie_ == other.trie_); }
+ bool operator!= (trie_iterator<const Trie, NonConstTrie> &other) const { return !(*this == other); }
+ bool operator!= (trie_iterator<Trie, NonConstTrie> &other) { return !(*this == other); }
+
+ trie_iterator<Trie,NonConstTrie> &
+ operator++ (int)
+ {
+ if (trie_->children_.size () > 0)
+ trie_ = &(*trie_->children_.begin ());
+ else
+ trie_ = goUp ();
+ return *this;
+ }
+
+ trie_iterator<Trie,NonConstTrie> &
+ operator++ ()
+ {
+ (*this)++;
+ return *this;
+ }
+
+private:
+ typedef typename boost::mpl::if_< boost::is_same<Trie, NonConstTrie>,
+ typename Trie::unordered_set::iterator,
+ typename Trie::unordered_set::const_iterator>::type set_iterator;
+
+ Trie* goUp ()
+ {
+ if (trie_->parent_ != 0)
+ {
+ // typename Trie::unordered_set::iterator item =
+ set_iterator item = const_cast<NonConstTrie*>(trie_)->parent_->children_.iterator_to (const_cast<NonConstTrie&> (*trie_));
+ item++;
+ if (item != trie_->parent_->children_.end ())
+ {
+ return &(*item);
+ }
+ else
+ {
+ trie_ = trie_->parent_;
+ return goUp ();
+ }
+ }
+ else
+ return 0;
+ }
+private:
+ Trie *trie_;
+};
+
+
+template<class Trie>
+class trie_point_iterator
+{
+private:
+ typedef typename boost::mpl::if_< boost::is_same<Trie, const Trie>,
+ typename Trie::unordered_set::const_iterator,
+ typename Trie::unordered_set::iterator>::type set_iterator;
+
+public:
+ trie_point_iterator () : trie_ (0) {}
+ trie_point_iterator (typename Trie::iterator item) : trie_ (item) {}
+ trie_point_iterator (Trie &item)
+ {
+ if (item.children_.size () != 0)
+ trie_ = &*item.children_.begin ();
+ else
+ trie_ = 0;
+ }
+
+ Trie & operator* () { return *trie_; }
+ const Trie & operator* () const { return *trie_; }
+ Trie * operator-> () { return trie_; }
+ const Trie * operator-> () const { return trie_; }
+ bool operator== (trie_point_iterator<const Trie> &other) const { return (trie_ == other.trie_); }
+ bool operator== (trie_point_iterator<Trie> &other) { return (trie_ == other.trie_); }
+ bool operator!= (trie_point_iterator<const Trie> &other) const { return !(*this == other); }
+ bool operator!= (trie_point_iterator<Trie> &other) { return !(*this == other); }
+
+ trie_point_iterator<Trie> &
+ operator++ (int)
+ {
+ if (trie_->parent_ != 0)
+ {
+ set_iterator item = trie_->parent_->children_.iterator_to (*trie_);
+ item ++;
+ if (item == trie_->parent_->children_.end ())
+ trie_ = 0;
+ else
+ trie_ = &*item;
+ }
+ else
+ {
+ trie_ = 0;
+ }
+ return *this;
+ }
+
+ trie_point_iterator<Trie> &
+ operator++ ()
+ {
+ (*this)++;
+ return *this;
+ }
+
+private:
+ Trie *trie_;
+};
+
+
+} // trie
+} // ndn
+
+#endif // NDN_TRIE_TRIE_H_
diff --git a/ndn-cpp/version.h b/ndn-cpp/version.h
new file mode 100644
index 0000000..34b65de
--- /dev/null
+++ b/ndn-cpp/version.h
@@ -0,0 +1,22 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_CXX_VERSION_H
+#define NDN_CXX_VERSION_H
+
+// NDN_CXX_VERSION % 100 is the minor version
+// NDN_CXX_VERSION / 100 % 1000 is the major version
+
+#define NDN_CXX_VERSION 0001
+
+#define NDN_CXX_VERSION_MAJOR 0
+#define NDN_CXX_VERSION_MINOR 1
+
+#endif // NDN_CXX_VERSION_H
diff --git a/ndn-cpp/wire/base.h b/ndn-cpp/wire/base.h
new file mode 100644
index 0000000..8247d09
--- /dev/null
+++ b/ndn-cpp/wire/base.h
@@ -0,0 +1,33 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_WIRE_BASE_H
+#define NDN_WIRE_BASE_H
+
+#include "ndn-cpp/fields/signature-sha256-with-rsa.h"
+
+namespace ndn {
+namespace wire {
+
+/**
+ * @brief Class defining interface for double dispatch pattern (=visitor pattern)
+ * to format variable fields in wire format
+ */
+class Base
+{
+public:
+ virtual void
+ appendSignature (std::ostream &os, const signature::Sha256WithRsa &signature, void *userData) = 0;
+};
+
+} // wire
+} // ndn
+
+#endif // NDN_WIRE_BASE_H
diff --git a/ndn-cpp/wire/ccnb.cc b/ndn-cpp/wire/ccnb.cc
new file mode 100644
index 0000000..86c3f5f
--- /dev/null
+++ b/ndn-cpp/wire/ccnb.cc
@@ -0,0 +1,259 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "ccnb.h"
+#include "ndn-cpp/error.h"
+
+#include <boost/lexical_cast.hpp>
+
+namespace ndn {
+namespace wire {
+
+#define CCN_TT_BITS 3
+#define CCN_TT_MASK ((1 << CCN_TT_BITS) - 1)
+#define CCN_MAX_TINY ((1 << (7-CCN_TT_BITS)) - 1)
+#define CCN_TT_HBIT ((unsigned char)(1 << 7))
+
+void
+Ccnb::appendBlockHeader (std::ostream &os, size_t val, Ccnb::ccn_tt tt)
+{
+ unsigned char buf[1+8*((sizeof(val)+6)/7)];
+ unsigned char *p = &(buf[sizeof(buf)-1]);
+ size_t n = 1;
+ p[0] = (CCN_TT_HBIT & ~Ccnb::CCN_CLOSE_TAG) |
+ ((val & CCN_MAX_TINY) << CCN_TT_BITS) |
+ (CCN_TT_MASK & tt);
+ val >>= (7-CCN_TT_BITS);
+ while (val != 0) {
+ (--p)[0] = (((unsigned char)val) & ~CCN_TT_HBIT) | Ccnb::CCN_CLOSE_TAG;
+ n++;
+ val >>= 7;
+ }
+ os.write (reinterpret_cast<const char*> (p), n);
+ // return n;
+}
+
+void
+Ccnb::appendNumber (std::ostream &os, uint32_t number)
+{
+ std::string numberStr = boost::lexical_cast<std::string> (number);
+
+ appendBlockHeader (os, numberStr.size (), Ccnb::CCN_UDATA);
+ numberStr.size ();
+ os.write (numberStr.c_str (), numberStr.size ());
+}
+
+void
+Ccnb::appendName (std::ostream &os, const Name &name)
+{
+ Ccnb::appendBlockHeader (os, Ccnb::CCN_DTAG_Name, Ccnb::CCN_DTAG); // <Name>
+ for (Name::const_iterator component = name.begin (); component != name.end (); component ++)
+ {
+ appendTaggedBlob (os, Ccnb::CCN_DTAG_Component, component->buf (), component->size ());
+ }
+ Ccnb::appendCloser (os); // </Name>
+}
+
+void
+Ccnb::appendTimestampBlob (std::ostream &os, const TimeInterval &time)
+{
+ // CCNx method function implements some markers, which are not really defined anywhere else...
+
+ // Determine miminal number of bytes required to store the timestamp
+ int required_bytes = 2; // 12 bits for fractions of a second, 4 bits left for seconds. Sometimes it is enough
+ intmax_t ts = time.total_seconds () >> 4;
+ for (; required_bytes < 7 && ts != 0; ts >>= 8) // not more than 6 bytes?
+ required_bytes++;
+
+ appendBlockHeader(os, required_bytes, Ccnb::CCN_BLOB);
+
+ // write part with seconds
+ ts = time.total_seconds () >> 4;
+ for (int i = 0; i < required_bytes - 2; i++)
+ os.put ( ts >> (8 * (required_bytes - 3 - i)) );
+
+ /* arithmetic contortions are to avoid overflowing 31 bits */
+ ts = ((time.total_seconds () & 15) << 12) +
+ (((time.total_nanoseconds () % 1000000000) / 5 * 8 + 195312) / 390625);
+ for (int i = required_bytes - 2; i < required_bytes; i++)
+ os.put ( ts >> (8 * (required_bytes - 1 - i)) );
+
+ // return len + required_bytes;
+}
+
+void
+Ccnb::appendExclude (std::ostream &os, const Exclude &exclude)
+{
+ appendBlockHeader (os, Ccnb::CCN_DTAG_Exclude, Ccnb::CCN_DTAG); // <Exclude>
+
+ for (Exclude::const_reverse_iterator item = exclude.rbegin (); item != exclude.rend (); item ++)
+ {
+ if (!item->first.empty ())
+ appendTaggedBlob (os, Ccnb::CCN_DTAG_Component, item->first.buf (), item->first.size ());
+ if (item->second)
+ {
+ appendBlockHeader (os, Ccnb::CCN_DTAG_Any, Ccnb::CCN_DTAG); // <Any>
+ appendCloser (os); // </Any>
+ }
+ }
+ appendCloser (os); // </Exclude>
+}
+
+void
+Ccnb::appendInterest (std::ostream &os, const Interest &interest)
+{
+ Ccnb::appendBlockHeader (os, Ccnb::CCN_DTAG_Interest, Ccnb::CCN_DTAG); // <Interest>
+
+ // this is used for now as an interest template. Name should be empty
+ // Ccnb::appendName (os, interest.getName ());
+ Ccnb::appendName (os, Name ()); // <Component>...</Component>...
+
+ if (interest.getMinSuffixComponents () != Interest::ncomps)
+ {
+ appendTaggedNumber (os, Ccnb::CCN_DTAG_MinSuffixComponents, interest.getMinSuffixComponents ());
+ }
+ if (interest.getMaxSuffixComponents () != Interest::ncomps)
+ {
+ appendTaggedNumber (os, Ccnb::CCN_DTAG_MaxSuffixComponents, interest.getMaxSuffixComponents ());
+ }
+ if (interest.getExclude ().size () > 0)
+ {
+ appendExclude (os, interest.getExclude ());
+ }
+ if (interest.getChildSelector () != Interest::CHILD_DEFAULT)
+ {
+ appendTaggedNumber (os, Ccnb::CCN_DTAG_ChildSelector, interest.getChildSelector ());
+ }
+ if (interest.getAnswerOriginKind () != Interest::AOK_DEFAULT)
+ {
+ appendTaggedNumber (os, Ccnb::CCN_DTAG_AnswerOriginKind, interest.getAnswerOriginKind ());
+ }
+ if (interest.getScope () != Interest::NO_SCOPE)
+ {
+ appendTaggedNumber (os, Ccnb::CCN_DTAG_Scope, interest.getScope ());
+ }
+ if (!interest.getInterestLifetime ().is_negative ())
+ {
+ Ccnb::appendBlockHeader (os, Ccnb::CCN_DTAG_InterestLifetime, Ccnb::CCN_DTAG);
+ Ccnb::appendTimestampBlob (os, interest.getInterestLifetime ());
+ Ccnb::appendCloser (os);
+ }
+ // if (GetNonce()>0)
+ // {
+ // uint32_t nonce = interest.GetNonce();
+ // appendTaggedBlob (start, Ccnb::CCN_DTAG_Nonce, nonce);
+ // }
+
+ // if (GetNack ()>0)
+ // {
+ // appendBlockHeader (start, Ccnb::CCN_DTAG_Nack, Ccnb::CCN_DTAG);
+ // appendNumber (start, interest.GetNack ());
+ // appendCloser (start);
+ // }
+ Ccnb::appendCloser (os); // </Interest>
+}
+
+static void *SIGNATURE_Block = 0;
+static void *SINATURE_INFO_PublisherPublicKeyDigest = reinterpret_cast<void *> (1);
+static void *SINATURE_INFO_KeyLocator = reinterpret_cast<void *> (2);
+
+static const char TYPES [][3] = {
+ {0x0C, 0x04, 0xC0},
+ {0x10, 0xD0, 0x91},
+ {0x18, 0xE3, 0x44},
+ {0x28, 0x46, 0x3F},
+ {0x2C, 0x83, 0x4A},
+ {0x34, 0x00, 0x8A}
+};
+
+void
+Ccnb::appendSignature (std::ostream &os, const signature::Sha256WithRsa &signature, void *userData)
+{
+ if (userData == SIGNATURE_Block)
+ {
+ Ccnb::appendBlockHeader (os, Ccnb::CCN_DTAG_Signature, Ccnb::CCN_DTAG); // <Signature>
+ // if (signature.getDigestAlgorithm () != "2.16.840.1.101.3.4.2.1")
+ // {
+ // appendString (os, Ccnb::CCN_DTAG_DigestAlgorithm, signature.getDigestAlgorithm ());
+ // }
+ appendTaggedBlob (os, Ccnb::CCN_DTAG_SignatureBits, signature.getSignatureBits ());
+ Ccnb::appendCloser (os); // </Signature>
+ }
+ else if (userData == SINATURE_INFO_PublisherPublicKeyDigest)
+ {
+ Ccnb::appendTaggedBlob (os, Ccnb::CCN_DTAG_PublisherPublicKeyDigest, signature.getPublisherKeyDigest ());
+ }
+ else if (userData == SINATURE_INFO_KeyLocator)
+ {
+ Ccnb::appendBlockHeader (os, Ccnb::CCN_DTAG_Signature, Ccnb::CCN_DTAG); // <Signature>
+ switch (signature.getKeyLocator ().getType ())
+ {
+ case KeyLocator::NOTSET:
+ break;
+ case KeyLocator::KEY:
+ Ccnb::appendTaggedBlob (os, Ccnb::CCN_DTAG_Key, signature.getKeyLocator ().getKey ());
+ break;
+ case KeyLocator::CERTIFICATE:
+ Ccnb::appendTaggedBlob (os, Ccnb::CCN_DTAG_Key, signature.getKeyLocator ().getCertificate ());
+ break;
+ case KeyLocator::KEYNAME:
+ Ccnb::appendBlockHeader (os, Ccnb::CCN_DTAG_KeyName, Ccnb::CCN_DTAG); // <KeyName>
+ Ccnb::appendName (os, signature.getKeyLocator ().getKeyName ());
+ Ccnb::appendCloser (os); // </KeyName>
+ break;
+ }
+ Ccnb::appendCloser (os); // </Signature>
+ }
+ // other cases should not be possible, but don't do anything
+}
+
+void
+Ccnb::appendData (std::ostream &os, const Data &data)
+{
+ if (!data.getSignature ())
+ BOOST_THROW_EXCEPTION (error::wire::Ccnb ()
+ << error::msg ("Signature is required, but not set"));
+
+ Ccnb::appendBlockHeader (os, Ccnb::CCN_DTAG_ContentObject, Ccnb::CCN_DTAG); // <ContentObject>
+
+ // necessary for now, because of the changed storage order
+ data.getSignature ()->doubleDispatch (os, *this, SIGNATURE_Block);
+
+ Ccnb::appendName (os, data.getName ());
+
+ Ccnb::appendBlockHeader (os, Ccnb::CCN_DTAG_SignedInfo, Ccnb::CCN_DTAG); // <SignedInfo>
+ data.getSignature ()->doubleDispatch (os, *this, SINATURE_INFO_PublisherPublicKeyDigest);
+
+ Ccnb::appendTimestampBlob (os, data.getContent ().getTimestamp ());
+
+ BOOST_ASSERT (sizeof (TYPES) == 3 * (static_cast<int> (Content::NACK)+1));
+ Ccnb::appendTaggedBlob (os, Ccnb::CCN_DTAG_Type, TYPES [data.getContent ().getType ()], 3);
+
+ if (data.getContent ().getFreshness () != Content::noFreshness)
+ {
+ Ccnb::appendTaggedNumber (os, Ccnb::CCN_DTAG_FreshnessSeconds,
+ data.getContent ().getFreshness ().total_seconds ());
+ }
+
+ if (data.getContent ().getFinalBlockId () != Content::noFinalBlock)
+ {
+ Ccnb::appendTaggedBlob (os, Ccnb::CCN_DTAG_FinalBlockID, data.getContent ().getFinalBlockId ());
+ }
+
+ data.getSignature ()->doubleDispatch (os, *this, SINATURE_INFO_KeyLocator);
+ Ccnb::appendCloser (os); // </SignedInfo>
+
+ Ccnb::appendTaggedBlob (os, Ccnb::CCN_DTAG_Content, data.content ());
+
+ Ccnb::appendCloser (os); // </ContentObject>
+}
+
+} // namespace wire
+} // namespace ndn
diff --git a/ndn-cpp/wire/ccnb.h b/ndn-cpp/wire/ccnb.h
new file mode 100644
index 0000000..fc99bad
--- /dev/null
+++ b/ndn-cpp/wire/ccnb.h
@@ -0,0 +1,350 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_WIRE_CCNB_H
+#define NDN_WIRE_CCNB_H
+
+#include "base.h"
+
+#include "ndn-cpp/interest.h"
+#include "ndn-cpp/data.h"
+
+namespace ndn {
+namespace wire {
+
+/**
+ * @brief Class for working with ccnb encoding
+ */
+class Ccnb : public Base
+{
+public:
+ /**
+ * \brief Type tag for a ccnb start marker.
+ *
+ * \see http://www.ccnx.org/releases/latest/doc/technical/DTAG.html
+ */
+ enum ccn_tt {
+ CCN_EXT, /**< starts composite extension - numval is subtype */
+ CCN_TAG, /**< starts composite - numval is tagnamelen-1 */
+ CCN_DTAG, /**< starts composite - numval is tagdict index (enum ccn_dtag) */
+ CCN_ATTR, /**< attribute - numval is attrnamelen-1, value follows */
+ CCN_DATTR, /**< attribute numval is attrdict index */
+ CCN_BLOB, /**< opaque binary data - numval is byte count */
+ CCN_UDATA, /**< UTF-8 encoded character data - numval is byte count */
+ CCN_NO_TOKEN /**< should not occur in encoding */
+ };
+
+ /** \brief CCN_CLOSE_TAG terminates composites */
+ enum {CCN_CLOSE_TAG = 0};
+
+ /**
+ * \brief DTAG identifies ccnb-encoded elements.
+ *
+ * \see http://www.ccnx.org/releases/latest/doc/technical/DTAG.html
+ */
+ enum ccn_dtag {
+ CCN_DTAG_Any = 13,
+ CCN_DTAG_Name = 14,
+ CCN_DTAG_Component = 15,
+ CCN_DTAG_Certificate = 16,
+ CCN_DTAG_Collection = 17,
+ CCN_DTAG_CompleteName = 18,
+ CCN_DTAG_Content = 19,
+ CCN_DTAG_SignedInfo = 20,
+ CCN_DTAG_ContentDigest = 21,
+ CCN_DTAG_ContentHash = 22,
+ CCN_DTAG_Count = 24,
+ CCN_DTAG_Header = 25,
+ CCN_DTAG_Interest = 26, /* 20090915 */
+ CCN_DTAG_Key = 27,
+ CCN_DTAG_KeyLocator = 28,
+ CCN_DTAG_KeyName = 29,
+ CCN_DTAG_Length = 30,
+ CCN_DTAG_Link = 31,
+ CCN_DTAG_LinkAuthenticator = 32,
+ CCN_DTAG_NameComponentCount = 33, /* DeprecatedInInterest */
+ CCN_DTAG_RootDigest = 36,
+ CCN_DTAG_Signature = 37,
+ CCN_DTAG_Start = 38,
+ CCN_DTAG_Timestamp = 39,
+ CCN_DTAG_Type = 40,
+ CCN_DTAG_Nonce = 41,
+ CCN_DTAG_Scope = 42,
+ CCN_DTAG_Exclude = 43,
+ CCN_DTAG_Bloom = 44,
+ CCN_DTAG_BloomSeed = 45,
+ CCN_DTAG_AnswerOriginKind = 47,
+ CCN_DTAG_InterestLifetime = 48,
+ CCN_DTAG_Witness = 53,
+ CCN_DTAG_SignatureBits = 54,
+ CCN_DTAG_DigestAlgorithm = 55,
+ CCN_DTAG_BlockSize = 56,
+ CCN_DTAG_FreshnessSeconds = 58,
+ CCN_DTAG_FinalBlockID = 59,
+ CCN_DTAG_PublisherPublicKeyDigest = 60,
+ CCN_DTAG_PublisherCertificateDigest = 61,
+ CCN_DTAG_PublisherIssuerKeyDigest = 62,
+ CCN_DTAG_PublisherIssuerCertificateDigest = 63,
+ CCN_DTAG_ContentObject = 64, /* 20090915 */
+ CCN_DTAG_WrappedKey = 65,
+ CCN_DTAG_WrappingKeyIdentifier = 66,
+ CCN_DTAG_WrapAlgorithm = 67,
+ CCN_DTAG_KeyAlgorithm = 68,
+ CCN_DTAG_Label = 69,
+ CCN_DTAG_EncryptedKey = 70,
+ CCN_DTAG_EncryptedNonceKey = 71,
+ CCN_DTAG_WrappingKeyName = 72,
+ CCN_DTAG_Action = 73,
+ CCN_DTAG_FaceID = 74,
+ CCN_DTAG_IPProto = 75,
+ CCN_DTAG_Host = 76,
+ CCN_DTAG_Port = 77,
+ CCN_DTAG_MulticastInterface = 78,
+ CCN_DTAG_ForwardingFlags = 79,
+ CCN_DTAG_FaceInstance = 80,
+ CCN_DTAG_ForwardingEntry = 81,
+ CCN_DTAG_MulticastTTL = 82,
+ CCN_DTAG_MinSuffixComponents = 83,
+ CCN_DTAG_MaxSuffixComponents = 84,
+ CCN_DTAG_ChildSelector = 85,
+ CCN_DTAG_RepositoryInfo = 86,
+ CCN_DTAG_Version = 87,
+ CCN_DTAG_RepositoryVersion = 88,
+ CCN_DTAG_GlobalPrefix = 89,
+ CCN_DTAG_LocalName = 90,
+ CCN_DTAG_Policy = 91,
+ CCN_DTAG_Namespace = 92,
+ CCN_DTAG_GlobalPrefixName = 93,
+ CCN_DTAG_PolicyVersion = 94,
+ CCN_DTAG_KeyValueSet = 95,
+ CCN_DTAG_KeyValuePair = 96,
+ CCN_DTAG_IntegerValue = 97,
+ CCN_DTAG_DecimalValue = 98,
+ CCN_DTAG_StringValue = 99,
+ CCN_DTAG_BinaryValue = 100,
+ CCN_DTAG_NameValue = 101,
+ CCN_DTAG_Entry = 102,
+ CCN_DTAG_ACL = 103,
+ CCN_DTAG_ParameterizedName = 104,
+ CCN_DTAG_Prefix = 105,
+ CCN_DTAG_Suffix = 106,
+ CCN_DTAG_Root = 107,
+ CCN_DTAG_ProfileName = 108,
+ CCN_DTAG_Parameters = 109,
+ CCN_DTAG_InfoString = 110,
+ CCN_DTAG_StatusResponse = 112,
+ CCN_DTAG_StatusCode = 113,
+ CCN_DTAG_StatusText = 114,
+ CCN_DTAG_Nack = 200,
+ CCN_DTAG_SequenceNumber = 256,
+ CCN_DTAG_CCNProtocolDataUnit = 17702112
+ };
+
+
+ /**
+ * @brief Append CCNB block header
+ * @param os output stream to write
+ * @param value dictionary id of the block header
+ * @param block_type Type of CCNB block
+ */
+ static void
+ appendBlockHeader (std::ostream &os, size_t value, ccn_tt block_type);
+
+ /**
+ * @brief Add number in CCNB encoding
+ * @param os output stream to write
+ * @param number Number to be written
+ *
+ * @returns written length
+ */
+ static void
+ appendNumber (std::ostream &os, uint32_t number);
+
+ /**
+ * @brief Append CCNB closer tag (size is 1)
+ * @param os output stream to write
+ */
+ inline static void
+ appendCloser (std::ostream &os);
+
+ /**
+ * @brief Append Name in CCNB encoding
+ * @param os output stream to write
+ * @param name constant reference to Name object
+ *
+ * @returns written length
+ */
+ static void
+ appendName (std::ostream &os, const Name &name);
+
+ /**
+ * Append a binary timestamp as a BLOB using the ccn binary
+ * Timestamp representation (12-bit fraction).
+ *
+ * @param os output stream to write
+ * @param time reference to time duration object
+ */
+ static void
+ appendTimestampBlob (std::ostream &os, const TimeInterval ×tamp);
+
+ /**
+ * Append a binary timestamp as a BLOB using the ccn binary
+ * Timestamp representation (12-bit fraction).
+ *
+ * @param os output stream to write
+ * @param time reference to Time (posix_time::ptime) object.
+ * This method automatically calculates duration between time and gregorian::date(1970,1,1)
+ * and calls the other version of the method
+ */
+ inline static void
+ appendTimestampBlob (std::ostream &os, const Time &time);
+
+ /**
+ * Append a tagged BLOB
+ *
+ * This is a ccnb-encoded element with containing the BLOB as content
+ *
+ * @param os output stream to write
+ * @param dtag is the element's dtag
+ * @param data points to the binary data
+ * @param size is the size of the data, in bytes
+ */
+ inline static void
+ appendTaggedBlob (std::ostream &os, ccn_dtag dtag, const void *data, size_t size);
+
+ /**
+ * Append a tagged BLOB
+ *
+ * This is a ccnb-encoded element with containing the BLOB as content
+ *
+ * @param os output stream to write
+ * @param dtag is the element's dtag
+ * @param blob reference to the data blob
+ */
+ inline static void
+ appendTaggedBlob (std::ostream &os, ccn_dtag dtag, const Blob &blob);
+
+ /**
+ * Append a tagged BLOB
+ *
+ * This is a ccnb-encoded element with containing the BLOB as content
+ *
+ * @param os output stream to write
+ * @param dtag is the element's dtag
+ * @param data points to the binary data
+ * @param size is the size of the data, in bytes
+ */
+ inline static void
+ appendTaggedNumber (std::ostream &os, ccn_dtag dtag, uint32_t number);
+
+ /**
+ * Append a tagged string (should be a valid UTF-8 coded string)
+ *
+ * This is a ccnb-encoded element with containing UDATA as content
+ *
+ * @param os output stream to write
+ * @param dtag is the element's dtag
+ * @param string UTF-8 string to be written
+ */
+ inline static void
+ appendString (std::ostream &os, ccn_dtag dtag, const std::string &string);
+
+ /**
+ * @brief Format interest in CCNb encoding
+ * @param os output stream to write
+ * @param interest Interest to be formatted
+ *
+ * @todo For now, this method is used to create Interest template, which doesn't output name to the stream
+ */
+ static void
+ appendInterest (std::ostream &os, const Interest &interest);
+
+ /**
+ * @brief Append exclude filter in CCNb encoding
+ * @param os output stream to write
+ * @param exclude Exclude filter to be formatted
+ */
+ static void
+ appendExclude (std::ostream &os, const Exclude &exclude);
+
+ /**
+ * @brief Append signature in SHA256withRSA format
+ */
+ virtual void
+ appendSignature (std::ostream &os, const signature::Sha256WithRsa &signature, void *userData);
+
+ /**
+ * @brief Format data in CCNb encoding
+ * @param os output stream to write
+ * @param data data to be formatted
+ */
+ void
+ appendData (std::ostream &os, const Data &data);
+};
+
+
+inline void
+Ccnb::appendCloser (std::ostream &os)
+{
+ os.put (Ccnb::CCN_CLOSE_TAG);
+}
+
+inline void
+Ccnb::appendTimestampBlob (std::ostream &os, const Time &time)
+{
+ appendTimestampBlob (os, time - time::UNIX_EPOCH_TIME);
+}
+
+inline void
+Ccnb::appendTaggedBlob (std::ostream &os, Ccnb::ccn_dtag dtag, const void *data, size_t size)
+{
+ appendBlockHeader (os, dtag, Ccnb::CCN_DTAG);
+ /* 2 */
+ if (size>0)
+ {
+ appendBlockHeader (os, size, Ccnb::CCN_BLOB);
+ os.write (reinterpret_cast<const char*> (data), size);
+ /* size */
+ }
+ appendCloser (os);
+ /* 1 */
+}
+
+inline void
+Ccnb::appendTaggedBlob (std::ostream &os, ccn_dtag dtag, const Blob &blob)
+{
+ appendTaggedBlob (os, dtag, blob.buf (), blob.size ());
+}
+
+inline void
+Ccnb::appendTaggedNumber (std::ostream &os, Ccnb::ccn_dtag dtag, uint32_t number)
+{
+ appendBlockHeader (os, dtag, Ccnb::CCN_DTAG);
+ {
+ appendNumber (os, number);
+ }
+ appendCloser (os);
+}
+
+inline void
+Ccnb::appendString (std::ostream &os, Ccnb::ccn_dtag dtag, const std::string &string)
+{
+ appendBlockHeader (os, dtag, Ccnb::CCN_DTAG);
+ {
+ appendBlockHeader (os, string.size (), Ccnb::CCN_UDATA);
+ os.write (string.c_str (), string.size ());
+ }
+ appendCloser (os);
+}
+
+} // wire
+} // ndn
+
+#endif // NDN_WIRE_CCNB_H
diff --git a/platforms/osx/keychain-osx.h b/platforms/osx/keychain-osx.h
new file mode 100644
index 0000000..7399e05
--- /dev/null
+++ b/platforms/osx/keychain-osx.h
@@ -0,0 +1,46 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_KEYCHAIN_OSX_H
+#define NDN_KEYCHAIN_OSX_H
+
+#include "ndn.cxx/security/keychain.h"
+
+namespace ndn {
+namespace keychain {
+
+class OSX : public Keychain
+{
+public:
+ OSX ();
+
+ virtual
+ ~OSX ();
+
+ virtual void
+ generateKeyPair (const Name &keyName);
+
+ virtual void
+ deleteKeyPair (const Name &keyName);
+
+ virtual void
+ deletePublicKey (const Name &keyName);
+
+ virtual Ptr<Blob>
+ getPublicKey (const Name &publicKeyName);
+
+private:
+ void *m_private;
+};
+
+} // keychain
+} // ndn
+
+#endif // NDN_KEYCHAIN_OSX_H
diff --git a/platforms/osx/keychain-osx.mm b/platforms/osx/keychain-osx.mm
new file mode 100644
index 0000000..15b9a0d
--- /dev/null
+++ b/platforms/osx/keychain-osx.mm
@@ -0,0 +1,245 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "keychain-osx.h"
+#include "ndn.cxx/error.h"
+#include "logging.h"
+
+#include <Foundation/Foundation.h>
+#include <AppKit/AppKit.h>
+#include <Security/Security.h>
+
+INIT_LOGGER ("Keychain.OSX");
+
+namespace ndn {
+
+namespace keychain {
+class OSX_Private
+{
+public:
+ static void
+ LogHumanError (OSStatus res, const std::string &errMsgStr)
+ {
+ CFStringRef errMsgPtr = SecCopyErrorMessageString (res, NULL);
+ char errMsg[1024];
+ CFStringGetCString (errMsgPtr, errMsg, 1024, kCFStringEncodingUTF8);
+ _LOG_DEBUG ("Open status: " << errMsg);
+
+ BOOST_THROW_EXCEPTION (error::Keychain ()
+ << error::msg (errMsgStr)
+ << error::msg (errMsg));
+ }
+
+ SecKeychainRef m_keychain;
+ SecKeychainRef m_origDefaultKeychain;
+ static const std::string s_keychainPath;
+};
+
+const std::string OSX_Private::s_keychainPath = "~/Library/Keychains/NDN.keychain";
+} // keychain
+
+
+
+keychain::OSX::OSX ()
+{
+ m_private = new OSX_Private ();
+ OSX_Private *self = reinterpret_cast<OSX_Private*> (m_private);
+
+ // AuthorizationRef authRef;
+ // AuthorizationItem right = { "system.keychain.modify", 0, NULL, 0 };
+ // AuthorizationRights rightSet = { 1, &right };
+
+ // /* Create authorization to access the system.keychain */
+ // OSStatus res1 = AuthorizationCreate(&rightSet, kAuthorizationEmptyEnvironment,
+ // kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed, &authRef);
+ // _LOG_DEBUG ("Auth status: " << res1);
+
+ SecKeychainSetUserInteractionAllowed (true);
+
+ OSStatus res = SecKeychainCreate (OSX_Private::s_keychainPath.c_str (),
+ 0, NULL, true, NULL,
+ &self->m_keychain);
+ _LOG_DEBUG ("Create status: " << res);
+
+ if (res == errSecDuplicateKeychain)
+ {
+ res = SecKeychainOpen (OSX_Private::s_keychainPath.c_str (),
+ &self->m_keychain);
+ _LOG_DEBUG ("Open status: " << res);
+ }
+
+ if (res != errSecSuccess)
+ OSX_Private::LogHumanError (res, "Cannot open or create OSX Keychain");
+
+ // res = SecKeychainUnlock (self->m_keychain, 0, NULL, false);
+ // _LOG_DEBUG ("Unlock status: " << res);
+
+ SecKeychainCopyDefault (&self->m_origDefaultKeychain);
+ SecKeychainSetDefault (self->m_keychain);
+}
+
+keychain::OSX::~OSX ()
+{
+ OSX_Private *self = reinterpret_cast<OSX_Private*> (m_private);
+
+ SecKeychainSetDefault (self->m_origDefaultKeychain);
+
+ CFRelease (self->m_keychain);
+ CFRelease (self->m_origDefaultKeychain);
+ delete self;
+}
+
+void
+keychain::OSX::generateKeyPair (const Name &keyName)
+{
+ const void * keys[] = {
+ kSecAttrLabel,
+ kSecAttrIsPermanent,
+ kSecAttrKeyType,
+ kSecAttrKeySizeInBits,
+ kSecAttrApplicationTag
+ };
+
+ std::string uri = keyName.toUri ();
+ CFStringRef label = CFStringCreateWithCString (NULL, uri.c_str (), kCFStringEncodingUTF8);
+ CFDataRef tag = CFDataCreate (NULL, reinterpret_cast<const unsigned char *> (uri.c_str ()), uri.size ());
+
+ int keySize = 2048;
+ const void * values[] = {
+ label,
+ kCFBooleanTrue,
+ kSecAttrKeyTypeRSA,
+ CFNumberCreate (NULL, kCFNumberIntType, &keySize),
+ tag
+ };
+
+ CFDictionaryRef dict = CFDictionaryCreate (NULL,
+ keys, values,
+ sizeof(keys) / sizeof(*keys),
+ NULL, NULL);
+
+ SecKeyRef publicKey, privateKey;
+
+ OSStatus res = SecKeyGeneratePair (dict, &publicKey, &privateKey);
+ _LOG_DEBUG ("GeneratePair stats: " << res);
+
+ if (res != errSecSuccess)
+ OSX_Private::LogHumanError (res, "Cannot generate public/private key pair");
+
+ CFRelease (publicKey);
+ CFRelease (privateKey);
+}
+
+void
+keychain::OSX::deleteKeyPair (const Name &keyName)
+{
+ const void * keys[] = {
+ kSecClass,
+ kSecAttrApplicationTag
+ };
+
+ std::string uri = keyName.toUri ();
+ CFDataRef tag = CFDataCreate (NULL, reinterpret_cast<const unsigned char *> (uri.c_str ()), uri.size ());
+
+ const void * values[] = {
+ kSecClassKey,
+ tag
+ };
+
+ CFDictionaryRef dict = CFDictionaryCreate (NULL,
+ keys, values,
+ sizeof(keys) / sizeof(*keys),
+ NULL, NULL);
+
+ OSStatus res = errSecSuccess;
+ while (res == errSecSuccess)
+ {
+ res = SecItemDelete (dict);
+ _LOG_DEBUG ("SecItemDelete status: " << res);
+ }
+
+ if (res != errSecItemNotFound)
+ OSX_Private::LogHumanError (res, "Error while deleting key " + keyName.toUri ());
+}
+
+void
+keychain::OSX::deletePublicKey (const Name &keyName)
+{
+ const void * keys[] = {
+ kSecClass,
+ kSecAttrKeyClass,
+ kSecAttrApplicationTag
+ };
+
+ std::string uri = keyName.toUri ();
+ CFDataRef tag = CFDataCreate (NULL, reinterpret_cast<const unsigned char *> (uri.c_str ()), uri.size ());
+
+ const void * values[] = {
+ kSecClassKey,
+ kSecAttrKeyClassPublic,
+ tag
+ };
+
+ CFDictionaryRef dict = CFDictionaryCreate (NULL,
+ keys, values,
+ sizeof(keys) / sizeof(*keys),
+ NULL, NULL);
+
+ OSStatus res = errSecSuccess;
+ while (res == errSecSuccess)
+ {
+ res = SecItemDelete (dict);
+ _LOG_DEBUG ("SecItemDelete status: " << res);
+ }
+
+ if (res != errSecItemNotFound)
+ OSX_Private::LogHumanError (res, "Error while deleting public key " + keyName.toUri ());
+}
+
+Ptr<Blob>
+keychain::OSX::getPublicKey (const Name &publicKeyName)
+{
+ const void * keys[] = {
+ kSecClass,
+ kSecAttrKeyType,
+ kSecAttrKeyClass,
+ kSecAttrApplicationTag,
+ kSecReturnData
+ };
+
+ std::string uri = publicKeyName.toUri ();
+ CFDataRef tag = CFDataCreate (NULL, reinterpret_cast<const unsigned char *> (uri.c_str ()), uri.size ());
+
+ const void * values[] = {
+ kSecClassKey,
+ kSecAttrKeyTypeRSA,
+ kSecAttrKeyClassPublic,
+ tag,
+ [NSNumber numberWithBool:YES]
+ };
+
+ CFDictionaryRef query = CFDictionaryCreate (NULL,
+ keys, values,
+ sizeof(keys) / sizeof(*keys),
+ NULL, NULL);
+
+ NSData* publicKey;
+ OSStatus res = SecItemCopyMatching (query, (CFTypeRef *)(&publicKey));
+ if (res != errSecSuccess)
+ OSX_Private::LogHumanError (res, "Cannot find public key " + publicKeyName.toUri ());
+
+ Ptr<Blob> retval (new Blob ([publicKey bytes], [publicKey length]));
+ _LOG_DEBUG ("Key size: " << [publicKey length]);
+ return retval;
+}
+
+/// @todo Release data structures after use
+
+} // ndn
diff --git a/scheduler/interval-generator.h b/scheduler/interval-generator.h
new file mode 100644
index 0000000..e480ecc
--- /dev/null
+++ b/scheduler/interval-generator.h
@@ -0,0 +1,33 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef INTERVAL_GENERATOR_H
+#define INTERVAL_GENERATOR_H
+
+#include <boost/shared_ptr.hpp>
+
+using namespace std;
+
+class IntervalGenerator;
+typedef boost::shared_ptr<IntervalGenerator> IntervalGeneratorPtr;
+
+class IntervalGenerator
+{
+public:
+ virtual ~IntervalGenerator () { }
+
+ virtual double
+ nextInterval() = 0;
+};
+
+
+#endif // INTERVAL_GENERATOR_H
diff --git a/scheduler/one-time-task.cc b/scheduler/one-time-task.cc
new file mode 100644
index 0000000..b3082af
--- /dev/null
+++ b/scheduler/one-time-task.cc
@@ -0,0 +1,43 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "one-time-task.h"
+#include "scheduler.h"
+
+OneTimeTask::OneTimeTask(const Callback &callback, const Tag &tag, const SchedulerPtr &scheduler, double delay)
+ : Task(callback, tag, scheduler)
+{
+ setTv(delay);
+}
+
+void
+OneTimeTask::run()
+{
+ if (!m_invoked)
+ {
+ m_callback();
+ m_invoked = true;
+ deregisterSelf();
+ }
+}
+
+void
+OneTimeTask::deregisterSelf()
+{
+ m_scheduler->deleteTask(m_tag);
+}
+
+void
+OneTimeTask::reset()
+{
+ m_invoked = false;
+}
diff --git a/scheduler/one-time-task.h b/scheduler/one-time-task.h
new file mode 100644
index 0000000..744ca90
--- /dev/null
+++ b/scheduler/one-time-task.h
@@ -0,0 +1,40 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef ONE_TIME_TASK_H
+#define ONE_TIME_TASK_H
+
+#include "task.h"
+
+class OneTimeTask : public Task
+{
+public:
+ OneTimeTask(const Callback &callback, const Tag &tag, const SchedulerPtr &scheduler, double delay);
+ virtual ~OneTimeTask(){}
+
+ // invoke callback and mark self as invoked and deregister self from scheduler
+ virtual void
+ run() _OVERRIDE;
+
+ // after reset, the task is marked as un-invoked and can be add to scheduler again, with same delay
+ // if not invoked yet, no effect
+ virtual void
+ reset() _OVERRIDE;
+
+private:
+ // this is to deregister itself from scheduler automatically after invoke
+ void
+ deregisterSelf();
+};
+
+
+#endif // EVENT_SCHEDULER_H
diff --git a/scheduler/periodic-task.cc b/scheduler/periodic-task.cc
new file mode 100644
index 0000000..110c4df
--- /dev/null
+++ b/scheduler/periodic-task.cc
@@ -0,0 +1,48 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "periodic-task.h"
+#include "logging.h"
+#include <utility>
+
+INIT_LOGGER ("Scheduler.PeriodicTask");
+
+PeriodicTask::PeriodicTask(const Callback &callback, const Tag &tag, const SchedulerPtr &scheduler,
+ IntervalGeneratorPtr generator)
+ : Task(callback, tag, scheduler)
+ , m_generator(generator)
+{
+}
+
+void
+PeriodicTask::run()
+{
+ if (!m_invoked)
+ {
+ m_invoked = true;
+ m_callback();
+
+ if (m_invoked)
+ {
+ // m_invoked getting back if it is rescheduled inside the callback
+ m_scheduler->rescheduleTask(m_tag);
+ }
+ }
+}
+
+void
+PeriodicTask::reset()
+{
+ m_invoked = false;
+ double interval = m_generator->nextInterval();
+ setTv(interval);
+}
diff --git a/scheduler/periodic-task.h b/scheduler/periodic-task.h
new file mode 100644
index 0000000..303dca4
--- /dev/null
+++ b/scheduler/periodic-task.h
@@ -0,0 +1,41 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef PERIODIC_TASK_H
+#define PERIODIC_TASK_H
+
+#include "task.h"
+#include "scheduler.h"
+#include "interval-generator.h"
+
+class PeriodicTask : public Task
+{
+public:
+ // generator is needed only when this is a periodic task
+ // two simple generators implementation (SimpleIntervalGenerator and RandomIntervalGenerator) are provided;
+ // if user needs more complex pattern in the intervals between calls, extend class IntervalGenerator
+ PeriodicTask(const Callback &callback, const Tag &tag, const SchedulerPtr &scheduler, IntervalGeneratorPtr generator);
+ virtual ~PeriodicTask(){}
+
+ // invoke callback, reset self and ask scheduler to schedule self with the next delay interval
+ virtual void
+ run() _OVERRIDE;
+
+ // set the next delay and mark as un-invoke
+ virtual void
+ reset() _OVERRIDE;
+
+private:
+ IntervalGeneratorPtr m_generator;
+};
+
+#endif // PERIODIC_TASK_H
diff --git a/scheduler/random-interval-generator.h b/scheduler/random-interval-generator.h
new file mode 100644
index 0000000..476578c
--- /dev/null
+++ b/scheduler/random-interval-generator.h
@@ -0,0 +1,80 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef RANDOM_INTERVAL_GENERATOR_H
+#define RANDOM_INTERVAL_GENERATOR_H
+
+#include "interval-generator.h"
+
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_real.hpp>
+#include <boost/random/variate_generator.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+// generates intervals with uniform distribution
+class RandomIntervalGenerator : public IntervalGenerator
+{
+public:
+ typedef enum
+ {
+ UP = 1,
+ DOWN = 2,
+ EVEN = 3
+ } Direction;
+
+public:
+ // percent is random-range/interval; e.g. if interval is 10 and you wish the random-range to be 2
+ // e.g. 9 ~ 11, percent = 0.2
+ // direction shifts the random range; e.g. in the above example, UP would produce a range of
+ // 10 ~ 12, DOWN of 8 ~ 10, and EVEN of 9 ~ 11
+ RandomIntervalGenerator(double interval, double percent, Direction direction = EVEN)
+ // : m_rng(time(NULL))
+ : m_rng (static_cast<int> (boost::posix_time::microsec_clock::local_time().time_of_day ().total_nanoseconds ()))
+ , m_dist(0.0, fractional(percent))
+ , m_random(m_rng, m_dist)
+ , m_direction(direction)
+ , m_percent(percent)
+ , m_interval(interval)
+ { }
+
+ virtual ~RandomIntervalGenerator(){}
+
+ virtual double
+ nextInterval() _OVERRIDE
+ {
+ 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;
+ }
+
+private:
+ 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::variate_generator<RNG_TYPE &, boost::uniform_real<> > m_random;
+ Direction m_direction;
+ double m_percent;
+ double m_interval;
+
+};
+#endif // RANDOM_INTERVAL_GENERATOR_H
diff --git a/scheduler/scheduler-all.h b/scheduler/scheduler-all.h
new file mode 100644
index 0000000..388a74c
--- /dev/null
+++ b/scheduler/scheduler-all.h
@@ -0,0 +1,24 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef SCHEDULE_ALL_H
+#define SCHEDULE_ALL_H
+
+#include "scheduler/interval-generator.h"
+#include "scheduler/one-time-task.h"
+#include "scheduler/periodic-task.h"
+#include "scheduler/random-interval-generator.h"
+#include "scheduler/scheduler.h"
+#include "scheduler/simple-interval-generator.h"
+#include "scheduler/task.h"
+
+#endif
diff --git a/scheduler/scheduler.cc b/scheduler/scheduler.cc
new file mode 100644
index 0000000..02ac0c0
--- /dev/null
+++ b/scheduler/scheduler.cc
@@ -0,0 +1,338 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "scheduler.h"
+#include "one-time-task.h"
+#include "periodic-task.h"
+#include "logging.h"
+
+#include <utility>
+#include <boost/make_shared.hpp>
+
+INIT_LOGGER ("Scheduler");
+
+using namespace std;
+using namespace boost;
+
+#define EVLOOP_NO_EXIT_ON_EMPTY 0x04
+
+static void
+dummyCallback(evutil_socket_t fd, short what, void *arg)
+{
+ // 1 year later, that was a long run for the app
+ // let's wait for another year
+ timeval tv;
+ tv.tv_sec = 365 * 24 * 3600;
+ tv.tv_usec = 0;
+ event *ev = *(event **)arg;
+ int res = evtimer_add(ev, &tv);
+}
+
+// IntervalGeneratorPtr
+// IntervalGenerator:: Null;
+
+void errorCallback(int err)
+{
+ _LOG_ERROR ("Fatal error: " << err);
+}
+
+Scheduler::Scheduler()
+ : m_running(false)
+ , m_executor(1)
+{
+ event_set_fatal_callback(errorCallback);
+ evthread_use_pthreads();
+ m_base = event_base_new();
+
+ // This is a hack to prevent event_base_loop from exiting;
+ // the flag EVLOOP_NO_EXIT_ON_EMPTY is somehow ignored, at least on Mac OS X
+ // it's going to be scheduled to 10 years later
+ timeval tv;
+ tv.tv_sec = 365 * 24 * 3600;
+ tv.tv_usec = 0;
+ m_ev = evtimer_new(m_base, dummyCallback, &m_ev);
+ int res = evtimer_add(m_ev, &tv);
+ if (res < 0)
+ {
+ _LOG_ERROR("heck");
+ }
+}
+
+Scheduler::~Scheduler()
+{
+ shutdown ();
+ evtimer_del(m_ev);
+ event_free(m_ev);
+ event_base_free(m_base);
+}
+
+void
+Scheduler::eventLoop()
+{
+ while(true)
+ {
+ if (event_base_loop(m_base, EVLOOP_NO_EXIT_ON_EMPTY) < 0)
+ {
+ _LOG_DEBUG ("scheduler loop break error");
+ }
+ else
+ {
+ _LOG_DEBUG ("scheduler loop break normal");
+ }
+
+ {
+ ScopedLock lock(m_mutex);
+ if (!m_running)
+ {
+ _LOG_DEBUG ("scheduler loop break normal");
+ break;
+ }
+ }
+
+ // just to prevent craziness in CPU usage which supposedly should not happen
+ // after adding the dummy event
+ usleep(1000);
+ }
+}
+
+void
+Scheduler::execute(Executor::Job job)
+{
+ m_executor.execute(job);
+}
+
+void
+Scheduler::start()
+{
+ ScopedLock lock(m_mutex);
+ if (!m_running)
+ {
+ m_thread = boost::thread(&Scheduler::eventLoop, this);
+ m_executor.start();
+ m_running = true;
+ }
+}
+
+void
+Scheduler::shutdown()
+{
+ bool breakAndWait = false;
+ {
+ ScopedLock lock (m_mutex);
+ if (m_running)
+ {
+ m_running = false;
+ breakAndWait = true;
+ }
+ }
+
+ if (breakAndWait)
+ {
+ event_base_loopbreak(m_base);
+ m_executor.shutdown();
+ m_thread.join();
+ }
+}
+
+TaskPtr
+Scheduler::scheduleOneTimeTask (SchedulerPtr scheduler, double delay,
+ const Task::Callback &callback, const Task::Tag &tag)
+{
+ TaskPtr task = make_shared<OneTimeTask> (callback, tag, scheduler, delay);
+ if (scheduler->addTask (task))
+ return task;
+ else
+ return TaskPtr ();
+}
+
+TaskPtr
+Scheduler::schedulePeriodicTask (SchedulerPtr scheduler, IntervalGeneratorPtr delayGenerator,
+ const Task::Callback &callback, const Task::Tag &tag)
+{
+ TaskPtr task = make_shared<PeriodicTask> (callback, tag, scheduler, delayGenerator);
+
+ if (scheduler->addTask (task))
+ return task;
+ else
+ return TaskPtr ();
+}
+
+bool
+Scheduler::addTask(TaskPtr newTask, bool reset/* = true*/)
+{
+ if (addToMap(newTask))
+ {
+ if (reset)
+ {
+ newTask->reset();
+ }
+ int res = evtimer_add(newTask->ev(), newTask->tv());
+ if (res < 0)
+ {
+ _LOG_ERROR ("evtimer_add failed for " << newTask->tag());
+ }
+ return true;
+ }
+ else
+ {
+ _LOG_ERROR ("fail to add task: " << newTask->tag());
+ }
+
+ return false;
+}
+
+void
+Scheduler::deleteTask(TaskPtr task)
+{
+ deleteTask (task->tag ());
+}
+
+void
+Scheduler::rescheduleTask(TaskPtr task)
+{
+ ScopedLock lock(m_mutex);
+ TaskMapIt it = m_taskMap.find(task->tag());
+ if (it != m_taskMap.end())
+ {
+ TaskPtr task = it->second;
+ task->reset();
+ int res = evtimer_add(task->ev(), task->tv());
+ if (res < 0)
+ {
+ _LOG_ERROR ("evtimer_add failed for " << task->tag());
+ }
+ }
+ else
+ {
+ addTask(task);
+ }
+}
+
+void
+Scheduler::rescheduleTask(const Task::Tag &tag)
+{
+ ScopedLock lock(m_mutex);
+ TaskMapIt it = m_taskMap.find(tag);
+ if (it != m_taskMap.end())
+ {
+ TaskPtr task = it->second;
+ task->reset();
+ int res = evtimer_add(task->ev(), task->tv());
+ if (res < 0)
+ {
+ cout << "evtimer_add failed for " << task->tag() << endl;
+ }
+ }
+}
+
+void
+Scheduler::rescheduleTaskAt (const Task::Tag &tag, double time)
+{
+ ScopedLock lock(m_mutex);
+ TaskMapIt it = m_taskMap.find (tag);
+ if (it != m_taskMap.end())
+ {
+ TaskPtr task = it->second;
+ task->reset();
+ task->setTv (time);
+
+ int res = evtimer_add(task->ev(), task->tv());
+ if (res < 0)
+ {
+ _LOG_ERROR ("evtimer_add failed for " << task->tag());
+ }
+ }
+ else
+ {
+ _LOG_ERROR ("Task for tag " << tag << " not found");
+ }
+}
+
+void
+Scheduler::rescheduleTaskAt (TaskPtr task, double time)
+{
+ ScopedLock lock(m_mutex);
+ TaskMapIt it = m_taskMap.find(task->tag());
+ if (it != m_taskMap.end())
+ {
+ TaskPtr task = it->second;
+ task->reset();
+ task->setTv (time);
+
+ int res = evtimer_add(task->ev(), task->tv());
+ if (res < 0)
+ {
+ _LOG_ERROR ("evtimer_add failed for " << task->tag());
+ }
+ }
+ else
+ {
+ task->setTv (time); // force different time
+ addTask (task, false);
+ }
+}
+
+
+bool
+Scheduler::addToMap(TaskPtr task)
+{
+ ScopedLock lock(m_mutex);
+ if (m_taskMap.find(task->tag()) == m_taskMap.end())
+ {
+ m_taskMap.insert(make_pair(task->tag(), task));
+ return true;
+ }
+ return false;
+}
+
+void
+Scheduler::deleteTask(const Task::Tag &tag)
+{
+ ScopedLock lock(m_mutex);
+ TaskMapIt it = m_taskMap.find(tag);
+ if (it != m_taskMap.end())
+ {
+ TaskPtr task = it->second;
+ evtimer_del(task->ev());
+ m_taskMap.erase(it);
+ }
+}
+
+void
+Scheduler::deleteTask(const Task::TaskMatcher &matcher)
+{
+ ScopedLock lock(m_mutex);
+ TaskMapIt it = m_taskMap.begin();
+ while(it != m_taskMap.end())
+ {
+ TaskPtr task = it->second;
+ if (matcher(task))
+ {
+ evtimer_del(task->ev());
+ // Use post increment; map.erase invalidate the iterator that is beening erased,
+ // but does not invalidate other iterators. This seems to be the convention to
+ // erase something from C++ STL map while traversing.
+ m_taskMap.erase(it++);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+}
+
+int
+Scheduler::size()
+{
+ ScopedLock lock(m_mutex);
+ return m_taskMap.size();
+}
diff --git a/scheduler/scheduler.h b/scheduler/scheduler.h
new file mode 100644
index 0000000..ffac5d2
--- /dev/null
+++ b/scheduler/scheduler.h
@@ -0,0 +1,138 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef SCHEDULER_H
+#define SCHEDULER_H
+
+#include <event2/event.h>
+#include <event2/thread.h>
+#include <event2/event-config.h>
+#include <event2/util.h>
+
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <boost/exception/all.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <math.h>
+#include <map>
+#include <sys/time.h>
+
+#include "scheduler/task.h"
+#include "scheduler/interval-generator.h"
+#include "executor/executor.h"
+
+class Scheduler;
+typedef boost::shared_ptr<Scheduler> SchedulerPtr;
+
+/**
+ * @brief Scheduler class
+ */
+class Scheduler
+{
+public:
+ Scheduler();
+ virtual ~Scheduler();
+
+ // start event scheduling
+ virtual void
+ start();
+
+ // stop event scheduling
+ virtual void
+ shutdown();
+
+ // helper method to schedule one-time task
+ static TaskPtr
+ scheduleOneTimeTask (SchedulerPtr scheduler, double delay, const Task::Callback &callback, const Task::Tag &tag);
+
+ // helper method to schedule periodic task
+ static TaskPtr
+ schedulePeriodicTask (SchedulerPtr scheduler, IntervalGeneratorPtr delayGenerator,
+ const Task::Callback &callback, const Task::Tag &tag);
+
+ // if task with the same tag exists, the task is not added and return false
+ virtual bool
+ addTask(TaskPtr task, bool reset = true);
+
+ // delete task by task->tag, regardless of whether it's invoked or not
+ virtual void
+ deleteTask(TaskPtr task);
+
+ // delete task by tag, regardless of whether it's invoked or not
+ // if no task is found, no effect
+ virtual void
+ deleteTask(const Task::Tag &tag);
+
+ // delete tasks by matcher, regardless of whether it's invoked or not
+ // this is flexiable in that you can use any form of criteria in finding tasks to delete
+ // but keep in mind this is a linear scan
+
+ // if no task is found, no effect
+ virtual void
+ deleteTask(const Task::TaskMatcher &matcher);
+
+ // task must already have been added to the scheduler, otherwise this method has no effect
+ // this is usually used by PeriodicTask
+ virtual void
+ rescheduleTask(const Task::Tag &tag);
+
+ // if the task is not pending, it will be added to the schedule queue
+ // if the task is pending, the delay is changed to the passed in delay
+ // e.g. if at second 0 task A with delay 5 is originally going to run at second 5 and
+ // rescheduleTask(A) is called at second 4, A will be reschedule to run
+ // at second 9
+ virtual void
+ rescheduleTask(TaskPtr task);
+
+ virtual void
+ rescheduleTaskAt (const Task::Tag &tag, double time);
+
+ virtual void
+ rescheduleTaskAt (TaskPtr task, double time);
+
+ void
+ execute(Executor::Job);
+
+ void
+ eventLoop();
+
+ event_base *
+ base() { return m_base; }
+
+ // used in test
+ int
+ size();
+
+protected:
+ bool
+ addToMap(TaskPtr task);
+
+protected:
+ typedef std::map<Task::Tag, TaskPtr> TaskMap;
+ typedef std::map<Task::Tag, TaskPtr>::iterator TaskMapIt;
+ typedef boost::recursive_mutex Mutex;
+ typedef boost::unique_lock<Mutex> ScopedLock;
+
+ TaskMap m_taskMap;
+ Mutex m_mutex;
+ volatile bool m_running;
+ event_base *m_base;
+ event *m_ev;
+ boost::thread m_thread;
+ Executor m_executor;
+};
+
+struct SchedulerException : virtual boost::exception, virtual std::exception { };
+
+#endif // SCHEDULER_H
diff --git a/scheduler/simple-interval-generator.h b/scheduler/simple-interval-generator.h
new file mode 100644
index 0000000..c7a9e77
--- /dev/null
+++ b/scheduler/simple-interval-generator.h
@@ -0,0 +1,31 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef SIMPLE_INTERVAL_GENERATOR_H
+#define SIMPLE_INTERVAL_GENERATOR_H
+
+#include "interval-generator.h"
+
+class SimpleIntervalGenerator : public IntervalGenerator
+{
+public:
+ SimpleIntervalGenerator(double interval) : m_interval (interval) {}
+ virtual ~SimpleIntervalGenerator() {}
+
+ virtual double
+ nextInterval() _OVERRIDE { return m_interval; }
+
+private:
+ double m_interval;
+};
+
+#endif // SIMPLE_INTERVAL_GENERATOR_H
diff --git a/scheduler/task.cc b/scheduler/task.cc
new file mode 100644
index 0000000..fa73490
--- /dev/null
+++ b/scheduler/task.cc
@@ -0,0 +1,74 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "task.h"
+#include "scheduler.h"
+
+static void
+eventCallback(evutil_socket_t fd, short what, void *arg)
+{
+ Task *task = static_cast<Task *>(arg);
+ task->execute();
+ task = NULL;
+}
+
+Task::Task(const Callback &callback, const Tag &tag, const SchedulerPtr &scheduler)
+ : m_callback(callback)
+ , m_tag(tag)
+ , m_scheduler(scheduler)
+ , m_invoked(false)
+ , m_event(NULL)
+ , m_tv(NULL)
+{
+ m_event = evtimer_new(scheduler->base(), eventCallback, this);
+ m_tv = new timeval;
+}
+
+Task::~Task()
+{
+ if (m_event != NULL)
+ {
+ event_free(m_event);
+ m_event = NULL;
+ }
+
+ if (m_tv != NULL)
+ {
+ delete m_tv;
+ m_tv = NULL;
+ }
+}
+
+void
+Task::setTv(double delay)
+{
+ // Alex: when using abs function, i would recommend use it with std:: prefix, otherwise
+ // the standard one may be used, which converts everything to INT, making a lot of problems
+ double intPart, fraction;
+ fraction = modf(std::abs(delay), &intPart);
+
+ m_tv->tv_sec = static_cast<int>(intPart);
+ m_tv->tv_usec = static_cast<int>((fraction * 1000000));
+}
+
+void
+Task::execute()
+{
+ // m_scheduler->execute(boost::bind(&Task::run, this));
+
+ // using a shared_ptr of this to ensure that when invoked from executor
+ // the task object still exists
+ // otherwise, it could be the case that the run() is to be executed, but before it
+ // could finish, the TaskPtr gets deleted from scheduler and the task object
+ // gets destroyed, causing crash
+ m_scheduler->execute(boost::bind(&Task::run, shared_from_this()));
+}
diff --git a/scheduler/task.h b/scheduler/task.h
new file mode 100644
index 0000000..bd14296
--- /dev/null
+++ b/scheduler/task.h
@@ -0,0 +1,94 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef TASK_H
+#define TASK_H
+
+#define _OVERRIDE
+#ifdef __GNUC__
+#if __GNUC_MAJOR >= 4 && __GNUC_MINOR__ >= 7
+ #undef _OVERRIDE
+ #define _OVERRIDE override
+#endif // __GNUC__ version
+#endif // __GNUC__
+
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <sys/time.h>
+
+//////////////////////////////////////////////////
+// forward declarations
+class Task;
+typedef boost::shared_ptr<Task> TaskPtr;
+
+class Scheduler;
+typedef boost::shared_ptr<Scheduler> SchedulerPtr;
+
+struct event;
+//////////////////////////////////////////////////
+
+
+/**
+ * @brief Base class for a task
+ */
+class Task : public boost::enable_shared_from_this<Task>
+{
+public:
+ // callback of this task
+ typedef boost::function<void ()> Callback;
+ // tag identifies this task, should be unique
+ typedef std::string Tag;
+ // used to match tasks
+ typedef boost::function<bool (const TaskPtr &task)> TaskMatcher;
+
+ // Task is associated with Schedulers due to the requirement that libevent event is associated with an libevent event_base
+ Task(const Callback &callback, const Tag &tag, const SchedulerPtr &scheduler);
+ virtual ~Task();
+
+ virtual void
+ run() = 0;
+
+ Tag
+ tag() { return m_tag; }
+
+ event *
+ ev() { return m_event; }
+
+ timeval *
+ tv() { return m_tv; }
+
+ // Task needs to be resetted after the callback is invoked if it is to be schedule again; just for safety
+ // it's called by scheduler automatically when addTask or rescheduleTask is called;
+ // Tasks should do preparation work here (e.g. set up new delay, etc. )
+ virtual void
+ reset() = 0;
+
+ // set delay
+ // This overrides whatever delay kept in m_tv
+ void
+ setTv(double delay);
+
+ void
+ execute();
+
+protected:
+ Callback m_callback;
+ Tag m_tag;
+ SchedulerPtr m_scheduler;
+ bool m_invoked;
+ event *m_event;
+ timeval *m_tv;
+};
+
+
+#endif // TASK_H
diff --git a/test/event-scheduler-tests.cc b/test/event-scheduler-tests.cc
new file mode 100644
index 0000000..fab5b76
--- /dev/null
+++ b/test/event-scheduler-tests.cc
@@ -0,0 +1,177 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "scheduler/scheduler-all.h"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/make_shared.hpp>
+#include <map>
+#include <unistd.h>
+
+using namespace boost;
+using namespace std;
+
+BOOST_AUTO_TEST_SUITE(SchedulerTests)
+
+map<string, int> table;
+
+void func(string str)
+{
+ map<string, int>::iterator it = table.find(str);
+ if (it == table.end())
+ {
+ table.insert(make_pair(str, 1));
+ }
+ else
+ {
+ int count = it->second;
+ count++;
+ table.erase(it);
+ table.insert(make_pair(str, count));
+ }
+}
+
+bool
+matcher(const TaskPtr &task)
+{
+ return task->tag() == "period" || task->tag() == "world";
+}
+
+BOOST_AUTO_TEST_CASE(SchedulerTest)
+{
+ SchedulerPtr scheduler(new Scheduler());
+ IntervalGeneratorPtr generator(new SimpleIntervalGenerator(0.2));
+
+ string tag1 = "hello";
+ string tag2 = "world";
+ string tag3 = "period";
+
+ TaskPtr task1(new OneTimeTask(boost::bind(func, tag1), tag1, scheduler, 0.5));
+ TaskPtr task2(new OneTimeTask(boost::bind(func, tag2), tag2, scheduler, 0.5));
+ TaskPtr task3(new PeriodicTask(boost::bind(func, tag3), tag3, scheduler, generator));
+
+ scheduler->start();
+ scheduler->addTask(task1);
+ scheduler->addTask(task2);
+ scheduler->addTask(task3);
+ BOOST_CHECK_EQUAL(scheduler->size(), 3);
+ usleep(600000);
+ BOOST_CHECK_EQUAL(scheduler->size(), 1);
+ scheduler->addTask(task1);
+ BOOST_CHECK_EQUAL(scheduler->size(), 2);
+ usleep(600000);
+ scheduler->addTask(task1);
+ BOOST_CHECK_EQUAL(scheduler->size(), 2);
+ usleep(400000);
+ scheduler->deleteTask(task1->tag());
+ BOOST_CHECK_EQUAL(scheduler->size(), 1);
+ usleep(200000);
+
+ scheduler->addTask(task1);
+ scheduler->addTask(task2);
+ BOOST_CHECK_EQUAL(scheduler->size(), 3);
+ usleep(100000);
+ scheduler->deleteTask(bind(matcher, _1));
+ BOOST_CHECK_EQUAL(scheduler->size(), 1);
+ usleep(1000000);
+
+ BOOST_CHECK_EQUAL(scheduler->size(), 0);
+ scheduler->addTask(task1);
+ usleep(400000);
+ BOOST_CHECK_EQUAL(scheduler->size(), 1);
+ scheduler->rescheduleTask(task1);
+ usleep(400000);
+ BOOST_CHECK_EQUAL(scheduler->size(), 1);
+ usleep(110000);
+ BOOST_CHECK_EQUAL(scheduler->size(), 0);
+
+
+ int hello = 0, world = 0, period = 0;
+
+ map<string, int>::iterator it;
+ it = table.find(tag1);
+ if (it != table.end())
+ {
+ hello = it->second;
+ }
+ it = table.find(tag2);
+ if (it != table.end())
+ {
+ world = it->second;
+ }
+ it = table.find(tag3);
+ if (it != table.end())
+ {
+ period = it->second;
+ }
+
+ // added five times, canceled once before invoking callback
+ BOOST_CHECK_EQUAL(hello, 4);
+ // added two times, canceled once by matcher before invoking callback
+ BOOST_CHECK_EQUAL(world, 1);
+ // invoked every 0.2 seconds before deleted by matcher
+ BOOST_CHECK_EQUAL(period, static_cast<int>((0.6 + 0.6 + 0.4 + 0.2 + 0.1) / 0.2));
+
+ scheduler->shutdown();
+}
+
+void reschedule();
+SchedulerPtr schd0(new Scheduler());
+int resCount;
+TaskPtr task0(new PeriodicTask(boost::bind(reschedule), "testtest", schd0, boost::make_shared<SimpleIntervalGenerator>(0.5)));
+void reschedule()
+{
+ schd0->rescheduleTask(task0);
+ resCount++;
+}
+
+BOOST_AUTO_TEST_CASE(RescheduleTest)
+{
+ resCount = 0;
+ schd0->start();
+ schd0->addTask(task0);
+ usleep(5100000);
+ BOOST_CHECK_EQUAL(resCount, 10);
+ schd0->shutdown();
+}
+
+BOOST_AUTO_TEST_CASE(GeneratorTest)
+{
+ double interval = 10;
+ double percent = 0.5;
+ int times = 10000;
+ IntervalGeneratorPtr generator(new RandomIntervalGenerator(interval, percent));
+ double sum = 0.0;
+ double min = 2 * interval;
+ double max = -1;
+ for (int i = 0; i < times; i++)
+ {
+ double next = generator->nextInterval();
+ sum += next;
+ if (next > max)
+ {
+ max = next;
+ }
+ if (next < min)
+ {
+ min = next;
+ }
+ }
+
+ BOOST_CHECK( abs(1.0 - (sum / static_cast<double>(times)) / interval) < 0.05);
+ BOOST_CHECK( min > interval * (1 - percent / 2.0));
+ BOOST_CHECK( max < interval * (1 + percent / 2.0));
+ BOOST_CHECK( abs(1.0 - ((max - min) / interval) / percent) < 0.05);
+
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/exclude-tests.cc b/test/exclude-tests.cc
new file mode 100644
index 0000000..882f5a6
--- /dev/null
+++ b/test/exclude-tests.cc
@@ -0,0 +1,104 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "ndn-cpp/fields/exclude.h"
+#include "ndn-cpp/error.h"
+
+#include <boost/test/unit_test.hpp>
+
+#include <boost/lexical_cast.hpp>
+
+using namespace ndn;
+using namespace std;
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE(ExcludeTests)
+
+BOOST_AUTO_TEST_CASE (Basic)
+{
+ Exclude e;
+ e.excludeOne (string ("b"));
+ BOOST_CHECK_EQUAL (e.size (), 1);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (e), "b ");
+
+ e.excludeOne (string ("d"));
+ BOOST_CHECK_EQUAL (e.size (), 2);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (e), "b d ");
+
+ e.excludeOne (string ("a"));
+ BOOST_CHECK_EQUAL (e.size (), 3);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (e), "a b d ");
+
+ e.excludeOne (string ("aa"));
+ BOOST_CHECK_EQUAL (e.size (), 4);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (e), "a b d aa ");
+
+ e.excludeOne (string ("cc"));
+ BOOST_CHECK_EQUAL (e.size (), 5);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (e), "a b d aa cc ");
+
+ e.excludeOne (string ("c"));
+ BOOST_CHECK_EQUAL (e.size (), 6);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (e), "a b c d aa cc ");
+}
+
+BOOST_AUTO_TEST_CASE (Ranges)
+{
+// example: ANY /b /d ANY /f
+
+ Exclude e;
+ e.excludeOne (string ("b0"));
+ BOOST_CHECK_EQUAL (e.size (), 1);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (e), "b0 ");
+
+ e.excludeRange (name::Component (), string ("b1"));
+ BOOST_CHECK_EQUAL (e.size (), 2);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (e), " ----> b1 ");
+
+ e.excludeRange (name::Component (), string ("c0"));
+ BOOST_CHECK_EQUAL (e.size (), 2);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (e), " ----> c0 ");
+
+ e.excludeRange (string ("a0"), string ("c0"));
+ BOOST_CHECK_EQUAL (e.size (), 2);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (e), " ----> c0 ");
+
+ e.excludeRange (string ("d0"), string ("e0"));
+ BOOST_CHECK_EQUAL (e.size (), 4);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (e), " ----> c0 d0 ----> e0 ");
+
+ e.excludeRange (string ("c1"), string ("d1"));
+ BOOST_CHECK_EQUAL (e.size (), 4);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (e), " ----> c0 c1 ----> e0 ");
+
+ e.excludeRange (string ("a1"), string ("d1"));
+ BOOST_CHECK_EQUAL (e.size (), 2);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (e), " ----> e0 ");
+
+ e.excludeBefore (string ("e2"));
+ BOOST_CHECK_EQUAL (e.size (), 2);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (e), " ----> e2 ");
+
+ e.excludeAfter (string ("f0"));
+ BOOST_CHECK_EQUAL (e.size (), 3);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (e), " ----> e2 f0 ----> ");
+
+ e.excludeAfter (string ("e5"));
+ BOOST_CHECK_EQUAL (e.size (), 3);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (e), " ----> e2 e5 ----> ");
+
+ e.excludeAfter (string ("b2"));
+ BOOST_CHECK_EQUAL (e.size (), 1);
+ BOOST_CHECK_EQUAL (lexical_cast<string> (e), " ----> ");
+
+ BOOST_REQUIRE_THROW (e.excludeRange (string ("d0"), string ("a0")), error::Exclude);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/executor-tests.cc b/test/executor-tests.cc
new file mode 100644
index 0000000..273f0c2
--- /dev/null
+++ b/test/executor-tests.cc
@@ -0,0 +1,72 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include <boost/test/unit_test.hpp>
+#include "executor/executor.h"
+
+#include "logging.h"
+
+INIT_LOGGER ("Test.Executor");
+
+using namespace boost;
+using namespace std;
+
+void timeConsumingJob ()
+{
+ _LOG_DEBUG ("Start sleep");
+ sleep(1);
+ _LOG_DEBUG ("Finish sleep");
+}
+
+BOOST_AUTO_TEST_CASE(TestExecutor)
+{
+ INIT_LOGGERS ();
+
+ {
+ Executor executor (3);
+ executor.start ();
+ Executor::Job job = bind(timeConsumingJob);
+
+ executor.execute(job);
+ executor.execute(job);
+
+ usleep(2000);
+ // both jobs should have been taken care of
+ BOOST_CHECK_EQUAL(executor.jobQueueSize(), 0);
+
+ usleep(500000);
+
+ // add four jobs while only one thread is idle
+ executor.execute(job);
+ executor.execute(job);
+ executor.execute(job);
+ executor.execute(job);
+
+ usleep(1000);
+ // three jobs should remain in queue
+ BOOST_CHECK_EQUAL(executor.jobQueueSize(), 3);
+
+ usleep(500000);
+ // two threads should have finished and
+ // take care of two queued jobs
+ BOOST_CHECK_EQUAL(executor.jobQueueSize(), 1);
+
+ // all jobs should have been fetched
+ usleep(501000);
+ BOOST_CHECK_EQUAL(executor.jobQueueSize(), 0);
+
+ executor.shutdown ();
+ } //separate scope to ensure that destructor is called
+
+
+ sleep(1);
+}
diff --git a/test/interest-tests.cc b/test/interest-tests.cc
new file mode 100644
index 0000000..7e56fd1
--- /dev/null
+++ b/test/interest-tests.cc
@@ -0,0 +1,95 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "ndn-cpp/wire/ccnb.h"
+#include "ndn-cpp/interest.h"
+
+#include <unistd.h>
+#include <fstream>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/make_shared.hpp>
+
+#include "logging.h"
+
+using namespace ndn;
+using namespace std;
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE(InterestTests)
+
+static const string Interest1 ("\x01\xD2\xF2\x00\x05\x9A\x8E\x32\x00\x05\xA2\x8E\x32\x00\x05\xAA\x8E\x31\x00\x02"
+ "\xFA\x8E\x34\x00\x02\xD2\x8E\x30\x00\x03\x82\x95\xA0\x00\x00\x00",
+ 36);
+
+static const string Interest2 ("\x01\xD2\xF2\x00\x05\x9A\x8E\x32\x00\x05\xA2\x8E\x32\x00\x03\x82\x95\xA0\x00\x00"
+ "\x00",
+ 21);
+
+static const string Interest3 ("\x01\xD2\xF2\x00\x05\x9A\x8E\x32\x00\x05\xA2\x8E\x32\x00\x02\xDA\xFA\xA5\x61\x6C" \
+ "\x65\x78\x00\xFA\xC5\x7A\x68\x65\x6E\x6B\x61\x69\x30\x00\xEA\x00\xFA\xC5\x7A\x68" \
+ "\x65\x6E\x6B\x61\x69\x31\x00\xFA\x01\x8D\x6C\x6F\x6F\x6F\x6F\x6F\x6F\x6F\x6F\x6F" \
+ "\x6F\x6F\x6F\x6F\x6F\x6E\x67\x00\xEA\x00\x00\x05\xAA\x8E\x31\x00\x02\xFA\x8E\x34" \
+ "\x00\x02\xD2\x8E\x30\x00\x03\x82\x95\xA0\x00\x00\x00", 93);
+
+BOOST_AUTO_TEST_CASE (Basic)
+{
+ INIT_LOGGERS ();
+
+ Interest i;
+ i.setName (Name ("/test"));
+ i.setMinSuffixComponents (2);
+ i.setMaxSuffixComponents (2);
+ i.setInterestLifetime (posix_time::seconds (10));
+ i.setScope (Interest::SCOPE_LOCAL_CCND);
+ i.setAnswerOriginKind (Interest::AOK_STALE);
+ i.setChildSelector (Interest::CHILD_RIGHT);
+ // i.setPublisherPublicKeyDigest (?);
+
+ ostringstream os;
+ wire::Ccnb::appendInterest (os, i);
+ string Interest0 = os.str ();
+ BOOST_CHECK_EQUAL_COLLECTIONS (Interest0.begin (), Interest0.end (),
+ Interest1.begin (), Interest1.end ());
+
+ i.getExclude ().excludeOne (name::Component ("alex"));
+ i.getExclude ().excludeRange (name::Component ("zhenkai0"), name::Component("zhenkai1"));
+ i.getExclude ().excludeAfter (name::Component ("loooooooooooooong"));
+
+ BOOST_CHECK_EQUAL (boost::lexical_cast<string> (i.getExclude ()), "alex zhenkai0 ----> zhenkai1 loooooooooooooong ----> ");
+
+ os.str (""); os.clear ();
+ wire::Ccnb::appendInterest (os, i);
+ Interest0 = os.str ();
+ BOOST_CHECK_EQUAL_COLLECTIONS (Interest0.begin (), Interest0.end (),
+ Interest3.begin (), Interest3.end ());
+}
+
+// BOOST_AUTO_TEST_CASE (Charbuf)
+// {
+// INIT_LOGGERS ();
+
+// Interest i;
+// i.setName (Name ("/test"));
+// i.setMinSuffixComponents (2);
+// i.setMaxSuffixComponents (2);
+// i.setInterestLifetime (posix_time::seconds (10));
+
+// charbuf_stream stream;
+// wire::Ccnb::appendInterest (stream, i);
+
+// BOOST_CHECK_EQUAL_COLLECTIONS (reinterpret_cast<char*> (stream.buf ().getBuf ()->buf),
+// reinterpret_cast<char*> (stream.buf ().getBuf ()->buf+stream.buf ().getBuf ()->length),
+// Interest2.begin (), Interest2.end ());
+
+// }
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/name-tests.cc b/test/name-tests.cc
new file mode 100644
index 0000000..1431f79
--- /dev/null
+++ b/test/name-tests.cc
@@ -0,0 +1,162 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include <sstream>
+#include "ndn-cpp/fields/name.h"
+#include "ndn-cpp/fields/name-component.h"
+#include "ndn-cpp/error.h"
+#include "ndn-cpp/wire/ccnb.h"
+
+#define BOOST_TEST_MAIN 1
+
+#include <boost/test/unit_test.hpp>
+
+using namespace ndn;
+using namespace std;
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE(NameTests)
+
+BOOST_AUTO_TEST_CASE (Component)
+{
+ name::Component x;
+ BOOST_CHECK_EQUAL (x.size (), 0);
+
+ x = name::Component ("test");
+ BOOST_CHECK_EQUAL (x.size (), 4);
+
+ x = name::Component ("%21test");
+ BOOST_CHECK_EQUAL (x.size (), 5);
+
+ BOOST_CHECK_EQUAL (x.toUri (), "!test");
+
+ x = name::Component ("%20test");
+ BOOST_CHECK_EQUAL (x.size (), 5);
+
+ BOOST_CHECK_EQUAL (x.toUri (), "%20test");
+}
+
+BOOST_AUTO_TEST_CASE (Basic)
+{
+ Name empty = Name ();
+ Name root = Name ("/");
+ BOOST_CHECK_EQUAL (empty, root);
+ BOOST_CHECK_EQUAL (empty, Name ("/"));
+ BOOST_CHECK_EQUAL (root.size(), 0);
+
+ empty.append ("hello");
+ empty.append ("world");
+ BOOST_CHECK_EQUAL (empty.size(), 2);
+ BOOST_CHECK_EQUAL (empty.toUri(), "/hello/world");
+ empty = empty + root;
+ BOOST_CHECK_EQUAL (empty.toUri(), "/hello/world");
+ BOOST_CHECK_EQUAL (empty.get (0).toUri (), "hello");
+ BOOST_CHECK_EQUAL (empty.getSubName(1, 1), Name("/world"));
+ Name name("/hello/world");
+ BOOST_CHECK_EQUAL (empty, name);
+ BOOST_CHECK_EQUAL (name, Name("/hello") + Name("/world"));
+
+ name.appendSeqNum (1);
+ name.appendSeqNum (255);
+ name.appendSeqNum (256);
+ name.appendSeqNum (1234567890);
+
+ BOOST_CHECK_EQUAL (name.toUri (), "/hello/world/%00%01/%00%FF/%00%01%00/%00I%96%02%D2");
+
+ BOOST_CHECK_EQUAL (name.get (5).toSeqNum (), 1234567890);
+ BOOST_CHECK_EQUAL (name.get (4).toSeqNum (), 256);
+ BOOST_CHECK_EQUAL (name.get (3).toSeqNum (), 255);
+ BOOST_CHECK_EQUAL (name.get (2).toSeqNum (), 1);
+
+ BOOST_CHECK_EQUAL (name.get (-1).toUri (), "%00I%96%02%D2");
+
+ BOOST_CHECK_EQUAL (Name ("/%00").get (0).toSeqNum (), 0);
+
+ const char tmp [] = {0, 1, 2, 3, 0x50};
+ BOOST_CHECK_EQUAL (Name ().append (tmp, sizeof(tmp)).toUri (), "/%00%01%02%03P");
+
+ string entree("entr\u00E9e");
+ BOOST_CHECK_EQUAL (Name ().append (entree.c_str(), entree.size()).toUri (), "/entr%C3%A9e");
+ Name entreeName("/entr%C3%A9e");
+ BOOST_CHECK_EQUAL_COLLECTIONS (entreeName.get(0).begin(), entreeName.get(0).end(), entree.begin(), entree.end() );
+
+ Name appendName ("/hello/you");
+ appendName.append (Name ("/hello/you/too"));
+ BOOST_CHECK_EQUAL (appendName.toUri (), "/hello/you/hello/you/too");
+
+ Name appendSelf ("/hello/you");
+ appendSelf.append (appendSelf);
+ BOOST_CHECK_EQUAL (appendSelf.toUri (), "/hello/you/hello/you");
+
+ Name withVersion ("/hello.txt/%FD%95-%25U1%DE%04/%00%01");
+ BOOST_REQUIRE_NO_THROW (withVersion.get (1).toVersion ());
+ BOOST_CHECK_EQUAL (withVersion.get (1).toVersion (), 1370203370106261);
+
+ BOOST_CHECK_EQUAL (Name("/!").toUri(), "/%21");
+}
+
+BOOST_AUTO_TEST_CASE (Advanced)
+{
+ BOOST_REQUIRE_THROW (Name (""), error::Name);
+ BOOST_REQUIRE_THROW (Name ("//"), error::Name);
+ BOOST_REQUIRE_THROW (Name ("ndn://"), error::Name);
+ BOOST_REQUIRE_THROW (Name ("bla"), error::Name);
+ BOOST_REQUIRE_THROW (Name ("bla/"), error::Name);
+ BOOST_REQUIRE_THROW (Name ("http:/test"), error::Name);
+
+ BOOST_CHECK_EQUAL (Name ("ndn:///").toUri (), "/");
+ BOOST_CHECK_EQUAL (Name ("ccnx:///").toUri (), "/");
+ BOOST_CHECK_EQUAL (Name ("/").toUri (), "/");
+ BOOST_CHECK_EQUAL (Name ("///").toUri (), "/");
+ BOOST_CHECK_EQUAL (Name ("////////////////////////////////////////////////").toUri (), "/");
+ BOOST_CHECK_EQUAL (Name ("ndn://bla:random@something-else:0000/actual/name").toUri (), "/actual/name");
+ BOOST_CHECK_EQUAL (Name ("/slash/").toUri (), "/slash");
+
+ BOOST_CHECK_EQUAL (Name ().append (".", 1).toUri (), "/...");
+ BOOST_CHECK_EQUAL (Name ("/.").get(0).size(), 0);
+ BOOST_CHECK_EQUAL (Name ("/..").get(0).size(), 0);
+ BOOST_CHECK_EQUAL (Name ("/...").get(0).size(), 0);
+ BOOST_CHECK_EQUAL (Name ("/....").get(0).size(), 1);
+
+ BOOST_CHECK_EQUAL (Name ().append ("", 0).toUri (), "/...");
+ const char tmp [] = {'.'};
+ BOOST_CHECK_EQUAL (Name ().append (tmp, sizeof(tmp)).toUri (), "/....");
+}
+
+BOOST_AUTO_TEST_CASE (Ordering)
+{
+ // check "canonical" ordering
+ BOOST_CHECK_EQUAL (Name ("/test"), Name ("/test"));
+ BOOST_CHECK_GE (Name ("/test"), Name ("/aaaa"));
+ BOOST_CHECK_GT (Name ("/test"), Name ("/aaaa"));
+ BOOST_CHECK_GT (Name ("/test/test/test"), Name ("/test/test"));
+ BOOST_CHECK_GE (Name ("/test/test/test"), Name ("/test/test"));
+ BOOST_CHECK_GE (Name ("/test/test/test"), Name ("/test/test/test"));
+
+ BOOST_CHECK_LE (Name ("/test"), Name ("/aaaaa"));
+ BOOST_CHECK_LT (Name ("/test"), Name ("/aaaaa"));
+ BOOST_CHECK_LT (Name ("/test/test"), Name ("/test/test/test"));
+ BOOST_CHECK_LE (Name ("/test/test"), Name ("/test/test/test"));
+ BOOST_CHECK_LE (Name ("/test/test/test"), Name ("/test/test/test"));
+}
+
+BOOST_AUTO_TEST_CASE (Encoding)
+{
+ std::stringbuf buffer;
+ std::ostream output (&buffer);
+
+ Name root = Name ("/");
+ wire::Ccnb::appendName(output, root);
+ BOOST_CHECK_EQUAL (buffer.str().size(), 2);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/security-tests.cc b/test/security-tests.cc
new file mode 100644
index 0000000..ec8415c
--- /dev/null
+++ b/test/security-tests.cc
@@ -0,0 +1,40 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Alexander Afanasyev
+ * Zhenkai Zhu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+// #include "platforms/osx/keychain-osx.h"
+#include "ndn-cpp/error.h"
+
+#include <boost/test/unit_test.hpp>
+
+#include <fstream>
+
+using namespace ndn;
+using namespace std;
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE(SecurityTests)
+
+BOOST_AUTO_TEST_CASE (Basic)
+{
+ // Ptr<Keychain> keychain;
+ // BOOST_CHECK_NO_THROW (keychain = Ptr<keychain::OSX>::Create ());
+
+ // Name keyName ("/my/private/key1");
+ // keychain->generateKeyPair (keyName);
+ // // keychain->deleteKeyPair (keyName);
+
+ // Ptr<Blob> key = keychain->getPublicKey (keyName);
+ // ofstream f ("out.pub");
+ // f.write (key->buf (), key->size ());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/test-boost-header-only.cpp b/test/test-boost-header-only.cpp
new file mode 100644
index 0000000..ebc8553
--- /dev/null
+++ b/test/test-boost-header-only.cpp
@@ -0,0 +1,36 @@
+/*
+ * File: test-no-boost.cpp
+ * Author: jefft0
+ *
+ * Created on June 10, 2013, 4:21 PM
+ */
+
+#include <cstdlib>
+#include <sstream>
+#include "ndn-cpp/fields/name.h"
+#include "ndn-cpp/fields/name-component.h"
+#include "ndn-cpp/interest.h"
+#include "ndn-cpp/wire/ccnb.h"
+
+using namespace std;
+using namespace ndn;
+
+/*
+ *
+ */
+int main(int argc, char** argv) {
+ Interest interest;
+ interest.setName(Name("/test"));
+ interest.setMinSuffixComponents(2);
+ interest.setMaxSuffixComponents(2);
+ interest.setInterestLifetime(boost::posix_time::seconds(10));
+ interest.setScope(Interest::SCOPE_LOCAL_CCND);
+ interest.setAnswerOriginKind(Interest::AOK_STALE);
+ interest.setChildSelector(Interest::CHILD_RIGHT);
+ // i.setPublisherPublicKeyDigest(?);
+ ostringstream binary;
+ wire::Ccnb::appendInterest(binary, interest);
+ cout << binary.str().size();
+
+ return 0;
+}
diff --git a/waf b/waf
new file mode 100755
index 0000000..240e86f
--- /dev/null
+++ b/waf
Binary files differ
diff --git a/waf-tools/sphinx_build.py b/waf-tools/sphinx_build.py
new file mode 100644
index 0000000..e1155d1
--- /dev/null
+++ b/waf-tools/sphinx_build.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Hans-Martin von Gaudecker, 2012
+
+"""
+Create Sphinx documentation. Currently only LaTeX and HTML are supported.
+
+The source file **must** be the conf.py file used by Sphinx. Everything
+else has defaults, passing in the parameters is optional.
+
+Usage for getting both html and pdf docs:
+
+ ctx(features='sphinx', source='docs/conf.py')
+ ctx(features='sphinx', source='docs/conf.py', buildername='latex')
+
+Optional parameters and their defaults:
+
+ * buildername: html
+ * srcdir: confdir (the directory where conf.py lives)
+ * outdir: confdir/buildername (in the build directory tree)
+ * doctreedir: outdir/.doctrees
+ * type: pdflatex (only applies to 'latex' builder)
+
+"""
+
+
+import os
+from waflib import Task, TaskGen, Errors, Logs
+
+class RunSphinxBuild(Task.Task):
+ def scan(self):
+ """Use Sphinx' internal environment to find the dependencies."""
+ s = self.sphinx_instance
+ msg, dummy, iterator = s.env.update(s.config, s.srcdir, s.doctreedir, s)
+ s.info(msg)
+ dep_nodes = []
+ for docname in s.builder.status_iterator(iterator, "reading sources... "):
+ filename = docname + s.config.source_suffix
+ dep_nodes.append(self.srcdir.find_node(filename))
+ for dep in s.env.dependencies.values():
+ # Need the 'str' call because Sphinx might return Unicode strings.
+ [dep_nodes.append(self.srcdir.find_node(str(d))) for d in dep]
+ return (dep_nodes, [])
+
+ def run(self):
+ """Run the Sphinx build."""
+ self.sphinx_instance.build(force_all=False, filenames=None)
+ return None
+
+ def post_run(self):
+ """Add everything found in the output directory tree as an output.
+ Not elegant, but pragmatic."""
+ for n in self.outdir.ant_glob("**", quiet=True, remove=False):
+ if n not in self.outputs: self.set_outputs(n)
+ super(RunSphinxBuild, self).post_run()
+
+
+def _get_main_targets(tg, s):
+ """Return some easy targets known from the Sphinx build environment **s.env**."""
+ out_dir = tg.bld.root.find_node(s.outdir)
+ tgt_nodes = []
+ if s.builder.name == "latex":
+ for tgt_info in s.env.config.latex_documents:
+ tgt_nodes.append(out_dir.find_or_declare(tgt_info[1]))
+ elif s.builder.name == "html":
+ suffix = getattr(s.env.config, "html_file_suffix", ".html")
+ tgt_name = s.env.config.master_doc + suffix
+ tgt_nodes.append(out_dir.find_or_declare(tgt_name))
+ else:
+ raise Errors.WafError("Sphinx builder not implemented: %s" % s.builder.name)
+ return tgt_nodes
+
+
+@TaskGen.feature("sphinx")
+@TaskGen.before_method("process_source")
+def apply_sphinx(tg):
+ """Set up the task generator with a Sphinx instance and create a task."""
+
+ from sphinx.application import Sphinx
+
+ # Put together the configuration based on defaults and tg attributes.
+ conf = tg.path.find_node(tg.source)
+ confdir = conf.parent.abspath()
+ buildername = getattr(tg, "buildername", "html")
+ srcdir = getattr(tg, "srcdir", confdir)
+ outdir = tg.path.find_or_declare (getattr(tg, "outdir", os.path.join(conf.parent.get_bld().abspath(), buildername))).abspath ()
+
+ doctreedir = getattr(tg, "doctreedir", os.path.join(outdir, ".doctrees"))
+
+ # Set up the Sphinx instance.
+ s = Sphinx (srcdir, confdir, outdir, doctreedir, buildername, status=None)
+
+ # Get the main targets of the Sphinx build.
+ tgt_nodes = _get_main_targets(tg, s)
+
+ # Create the task and set the required attributes.
+ task = tg.create_task("RunSphinxBuild", src=conf, tgt=tgt_nodes)
+ task.srcdir = tg.bld.root.find_node(s.srcdir)
+ task.outdir = tg.bld.root.find_node(s.outdir)
+ task.sphinx_instance = s
+
+ # Build pdf if we have the LaTeX builder, allow for building with xelatex.
+ if s.builder.name == "latex":
+ compile_type = getattr(tg, "type", "pdflatex")
+ tg.bld(features="tex", type=compile_type, source=tgt_nodes, name="sphinx_pdf", prompt=0)
+
+ # Bypass the execution of process_source by setting the source to an empty list
+ tg.source = []
diff --git a/waf-tools/tinyxml.py b/waf-tools/tinyxml.py
new file mode 100644
index 0000000..3908b38
--- /dev/null
+++ b/waf-tools/tinyxml.py
@@ -0,0 +1,76 @@
+#! /usr/bin/env python
+# encoding: utf-8
+
+'''
+
+When using this tool, the wscript will look like:
+
+ def options(opt):
+ opt.tool_options('tinyxml', tooldir=["waf-tools"])
+
+ def configure(conf):
+ conf.load('compiler_cxx tiny')
+
+ def build(bld):
+ bld(source='main.cpp', target='app', use='TINYXML')
+
+Options are generated, in order to specify the location of tinyxml includes/libraries.
+
+
+'''
+import sys
+import re
+from waflib import Utils,Logs,Errors
+from waflib.Configure import conf
+TINYXML_DIR=['/usr','/usr/local','/opt/local','/sw']
+TINYXML_VERSION_FILE='tinyxml.h'
+TINYXML_VERSION_CODE='''
+#include <iostream>
+#include <tinyxml.h>
+int main() { std::cout << TIXML_MAJOR_VERSION << "." << TIXML_MINOR_VERSION << "." << TIXML_PATCH_VERSION; }
+'''
+
+def options(opt):
+ opt.add_option('--tinyxml',type='string',default='',dest='tinyxml_dir',help='''path to where TinyXML is installed, e.g. /usr/local''')
+@conf
+def __tinyxml_get_version_file(self,dir):
+ try:
+ return self.root.find_dir(dir).find_node('%s/%s' % ('include', TINYXML_VERSION_FILE))
+ except:
+ return None
+@conf
+def tinyxml_get_version(self,dir):
+ val=self.check_cxx(fragment=TINYXML_VERSION_CODE,includes=['%s/%s' % (dir, 'include')], execute=True, define_ret = True, mandatory=True)
+ return val
+@conf
+def tinyxml_get_root(self,*k,**kw):
+ root=k and k[0]or kw.get('path',None)
+ # Logs.pprint ('RED', ' %s' %root)
+ if root and self.__tinyxml_get_version_file(root):
+ return root
+ for dir in TINYXML_DIR:
+ if self.__tinyxml_get_version_file(dir):
+ return dir
+ if root:
+ self.fatal('TinyXML not found in %s'%root)
+ else:
+ self.fatal('TinyXML not found, please provide a --tinyxml argument (see help)')
+@conf
+def check_tinyxml(self,*k,**kw):
+ if not self.env['CXX']:
+ self.fatal('load a c++ compiler first, conf.load("compiler_cxx")')
+
+ var=kw.get('uselib_store','TINYXML')
+ self.start_msg('Checking TinyXML')
+ root = self.tinyxml_get_root(*k,**kw);
+ self.env.TINYXML_VERSION=self.tinyxml_get_version(root)
+
+ self.env['INCLUDES_%s'%var]= '%s/%s' % (root, "include");
+ self.env['LIB_%s'%var] = "tinyxml"
+ self.env['LIBPATH_%s'%var] = '%s/%s' % (root, "lib")
+
+ self.end_msg(self.env.TINYXML_VERSION)
+ if Logs.verbose:
+ Logs.pprint('CYAN',' TinyXML include : %s'%self.env['INCLUDES_%s'%var])
+ Logs.pprint('CYAN',' TinyXML lib : %s'%self.env['LIB_%s'%var])
+ Logs.pprint('CYAN',' TinyXML libpath : %s'%self.env['LIBPATH_%s'%var])
diff --git a/wscript b/wscript
new file mode 100644
index 0000000..ef26082
--- /dev/null
+++ b/wscript
@@ -0,0 +1,169 @@
+# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+VERSION='0.6.0'
+
+from waflib import Build, Logs, Utils, Task, TaskGen, Configure
+
+def options(opt):
+ opt.add_option('--debug',action='store_true',default=False,dest='debug',help='''debugging mode''')
+ opt.add_option('--test', action='store_true',default=False,dest='_test',help='''build unit tests''')
+ opt.add_option('--log4cxx', action='store_true',default=False,dest='log4cxx',help='''Compile with log4cxx logging support''')
+
+ opt.load('compiler_c compiler_cxx boost ccnx doxygen gnu_dirs c_osx')
+ opt.load('tinyxml', tooldir=['waf-tools'])
+
+def configure(conf):
+ conf.load("compiler_c compiler_cxx boost ccnx gnu_dirs tinyxml doxygen c_osx")
+
+ if conf.options.debug:
+ conf.define ('_DEBUG', 1)
+ conf.add_supported_cxxflags (cxxflags = ['-O0',
+ '-Wall',
+ '-Wno-unused-variable',
+ '-g3',
+ '-Wno-unused-private-field', # only clang supports
+ '-fcolor-diagnostics', # only clang supports
+ '-Qunused-arguments' # only clang supports
+ ])
+ else:
+ conf.add_supported_cxxflags (cxxflags = ['-O3', '-g'])
+
+ # if Utils.unversioned_sys_platform () == "darwin":
+ # conf.check_cxx(framework_name='Foundation', uselib_store='OSX_FOUNDATION', mandatory=True, compile_filename='test.mm')
+ # # conf.check_cxx(framework_name='AppKit', uselib_store='OSX_APPKIT', mandatory=True, compile_filename='test.mm')
+ # conf.check_cxx(framework_name='Security', uselib_store='OSX_SECURITY', define_name='HAVE_SECURITY',
+ # use="OSX_FOUNDATION", mandatory=True, compile_filename='test.mm')
+
+ conf.define ("NDN_CXX_VERSION", VERSION)
+
+ conf.check_cfg(package='libevent', args=['--cflags', '--libs'], uselib_store='LIBEVENT', mandatory=True)
+ conf.check_cfg(package='libevent_pthreads', args=['--cflags', '--libs'], uselib_store='LIBEVENT_PTHREADS', mandatory=True)
+
+ if not conf.check_cfg(package='openssl', args=['--cflags', '--libs'], uselib_store='SSL', mandatory=False):
+ libcrypto = conf.check_cc(lib='crypto',
+ header_name='openssl/crypto.h',
+ define_name='HAVE_SSL',
+ uselib_store='SSL')
+ else:
+ conf.define ("HAVE_SSL", 1)
+ if not conf.get_define ("HAVE_SSL"):
+ conf.fatal ("Cannot find SSL libraries")
+
+ conf.check_cfg(package="libcrypto", args=['--cflags', '--libs'], uselib_store='CRYPTO', mandatory=True)
+
+ if conf.options.log4cxx:
+ conf.check_cfg(package='liblog4cxx', args=['--cflags', '--libs'], uselib_store='LOG4CXX', mandatory=True)
+ conf.define ("HAVE_LOG4CXX", 1)
+
+ conf.check_tinyxml(path=conf.options.tinyxml_dir)
+ conf.check_doxygen(mandatory=False)
+
+ conf.check_boost(lib='system test iostreams filesystem thread date_time')
+
+ boost_version = conf.env.BOOST_VERSION.split('_')
+ if int(boost_version[0]) < 1 or int(boost_version[1]) < 46:
+ Logs.error ("Minumum required boost version is 1.46")
+ return
+
+ conf.check_ccnx (path=conf.options.ccnx_dir)
+
+ if conf.options._test:
+ conf.define ('_TESTS', 1)
+ conf.env.TEST = 1
+
+ conf.write_config_header('config.h')
+
+def build (bld):
+ executor = bld.objects (
+ target = "executor",
+ features = ["cxx"],
+ cxxflags = "-fPIC",
+ source = bld.path.ant_glob(['executor/**/*.cc']),
+ use = 'BOOST BOOST_THREAD LIBEVENT LIBEVENT_PTHREADS LOG4CXX',
+ includes = ".",
+ )
+
+ scheduler = bld.objects (
+ target = "scheduler",
+ features = ["cxx"],
+ cxxflags = "-fPIC",
+ source = bld.path.ant_glob(['scheduler/**/*.cc']),
+ use = 'BOOST BOOST_THREAD LIBEVENT LIBEVENT_PTHREADS LOG4CXX executor',
+ includes = ".",
+ )
+
+ libndn_cxx = bld (
+ target="ndn.cxx",
+ features=['cxx', 'cxxshlib'],
+ source = bld.path.ant_glob(['ndn.cxx/**/*.cpp', 'ndn.cxx/**/*.cc',
+ 'logging.cc',
+ 'libndn.cxx.pc.in']),
+ use = 'CRYPTO TINYXML BOOST BOOST_THREAD SSL CCNX LOG4CXX scheduler executor',
+ includes = ".",
+ )
+
+ # if Utils.unversioned_sys_platform () == "darwin":
+ # libndn_cxx.mac_app = True
+ # libndn_cxx.source += bld.path.ant_glob (['platforms/osx/**/*.mm'])
+ # libndn_cxx.use += " OSX_FOUNDATION OSX_SECURITY"
+
+ # Unit tests
+ if bld.env['TEST']:
+ unittests = bld.program (
+ target="unit-tests",
+ features = "cxx cxxprogram",
+ defines = "WAF",
+ source = bld.path.ant_glob(['test/*.cc']),
+ use = 'BOOST_TEST BOOST_FILESYSTEM BOOST_DATE_TIME LOG4CXX ndn.cxx',
+ includes = ".",
+ install_prefix = None,
+ )
+
+ headers = bld.path.ant_glob(['ndn.cxx.h', 'ndn.cxx/**/*.h'])
+ bld.install_files("%s" % bld.env['INCLUDEDIR'], headers, relative_trick=True)
+
+@Configure.conf
+def add_supported_cxxflags(self, cxxflags):
+ """
+ Check which cxxflags are supported by compiler and add them to env.CXXFLAGS variable
+ """
+ self.start_msg('Checking allowed flags for c++ compiler')
+
+ supportedFlags = []
+ for flag in cxxflags:
+ if self.check_cxx (cxxflags=[flag], mandatory=False):
+ supportedFlags += [flag]
+
+ self.end_msg (' '.join (supportedFlags))
+ self.env.CXXFLAGS += supportedFlags
+
+
+# doxygen docs
+from waflib.Build import BuildContext
+class doxy (BuildContext):
+ cmd = "doxygen"
+ fun = "doxygen"
+
+def doxygen (bld):
+ if not bld.env.DOXYGEN:
+ bld.fatal ("ERROR: cannot build documentation (`doxygen' is not found in $PATH)")
+ bld (features="doxygen",
+ doxyfile='doc/doxygen.conf')
+
+# doxygen docs
+from waflib.Build import BuildContext
+class sphinx (BuildContext):
+ cmd = "sphinx"
+ fun = "sphinx"
+
+def sphinx (bld):
+ bld.load('sphinx_build', tooldir=['waf-tools'])
+
+ bld (features="sphinx",
+ outdir = "doc/html",
+ source = "doc/source/conf.py")
+
+
+@TaskGen.extension('.mm')
+def mm_hook(self, node):
+ """Alias .mm files to be compiled the same as .cc files, gcc will do the right thing."""
+ return self.create_compiled_task('cxx', node)