22 Commits

Author SHA1 Message Date
Teng Liang 799390a4e4 ndnpeek: add --link-file option
Change-Id: Idbf283a5ae23be76f9eb2752906c8aec21b2fede
Refs: #3112
2016-03-14 08:06:20 -07:00
Vince Lehman f8852b3206 dump: Update docs to include NACK capture feature
refs: #3463

Change-Id: I01618d03afdeecb329c74a3575b242b3d501abb1
2016-03-11 12:04:03 -08:00
Teng Liang d4ab87fb12 ndnpeek: switch from getopt to boost::program_options
Change-Id: Idf47e6b6eb6c082708e423c16f7eb503b81deabd
Refs: #3112
2016-03-10 13:55:35 -07:00
Vince Lehman 277ecf085e dump: Capture and print network NACK packets
refs: #3463

Change-Id: I3aed0d3668378305404f9713cc110e13eec434e5
2016-03-06 22:01:16 -08:00
Alexander Afanasyev 821a01431b build: Fix compatibility with Python 3
Change-Id: I5a7b332eb43b44ca528c27db762bf8e7e1f022e6
Refs: #3499
2016-03-03 09:34:36 -08:00
Junxiao Shi ae2c9f73ad ping: protocol definition
refs #3460

Change-Id: I539f2e5144a8a5370aa1f91201eaa608d5f1ecc1
2016-02-16 09:03:24 -07:00
Andrea Tosatto 672b9a7093 chunks: segmented file transfer
refs #3071

Change-Id: I88e4fc1a8e33a0d61a95e2291cccc7b998647489
2016-01-19 16:26:15 +01:00
Davide Pesavento 28ae2cbee0 build: fix missing tool name in 'configure --help' output
Change-Id: I00a106c6a8c4c6ebbbfcf1a0db1ad98a66af18f6
2016-01-14 22:30:39 +01:00
Davide Pesavento 3e79c9cda4 build: enable -Wextra by default
Change-Id: I0e4615d4dfbbf0a7bf3e509bf2ad3d72b92993cb
Refs: #3293
2015-11-01 21:40:58 +01:00
Junxiao Shi e02fb52090 peek: verbose output
refs #3268

Change-Id: I59fd0e4f6537088346edaff8e785e6f8c8fffa6d
2015-10-18 08:45:09 -07:00
Junxiao Shi c8a0a25a67 build: disable clang's unused-local-typedef warning and keyword-macro error
unused-local-typedef is disabled completely.
keyword-macro is downgraded from an error to a warning.

This commit also enables color diagnostics on release builds.

refs #3209 #3235

Change-Id: Ibce2da95dffb88abc384e6c98911d4ac900a880a
2015-10-05 16:43:34 -07:00
Alexander Afanasyev ef1e276b11 Bump version to 0.2
Change-Id: Ie4ac30cd0ada494f8b7f5d6d77218e6b60a5e800
Refs: #3132
2015-08-31 14:50:15 -07:00
Alexander Afanasyev 8a3081f973 ci: Fixes build matrix for Travis-CI checks
Change-Id: I4f589b3575264ecf5aa85468999836ec44dfa12a
Refs: #3150
2015-08-31 13:27:15 -07:00
Alexander Afanasyev 1e7a7b20c9 ping: Code refactoring
Change-Id: I8b4e2c9dd3ba3adfae8d296a5635b048b35cf593
Refs: #3137
2015-08-31 09:29:06 -07:00
Alexander Afanasyev 7f43c53c2a dissect-wireshark: Add support for dissecting of Ethernet frames (ethertype=0x8624)
Change-Id: I1cc8898076bd3f4d615045514907095c6a5f9149
Refs: #3092
2015-08-14 21:53:10 -07:00
Alexander Afanasyev 357c205aa6 dissect-wireshark: Refactored dissector implementation
Change-Id: I913044e5f5e9f42dc62d5d81da758f12177bb149
Refs: #3092
2015-08-12 23:18:11 -07:00
Alexander Afanasyev 6fbb7b4594 dissect-wireshark: Lua-based Wireshark dissector for NDN packets
Change-Id: Ic81f3050d5f1480e9e98f3d54b01ca2cffca56b4
Refs: #3092
2015-08-10 21:38:08 -07:00
Eric Newberry a93680e5b7 ping: Tests for Ping and PingServer
This commit includes minor refactoring in Ping and PingServer to support unit testing

refs #2796

Change-Id: Id0172486aa07e129a90091d72594fbccbb5dbc06
2015-07-27 13:11:00 -07:00
Yingdi Yu 0a312e5126 pib: Adapt code into ndn-tools conventions
Changes include:
1. license boilerplate
2. include guards
3. test suite names
4. return value of main function
5. README.md

Change-Id: I14289402475b591d7cdce7390cec5e3c0b6befe5
Refs: #3018
2015-07-23 12:17:08 -07:00
Yingdi Yu 77627ab8ce Move pib service from ndn-cxx to ndn-tools
Code is copied from ndn-cxx:commit:e1c8c4cfffb33dca13c8ca7d7ef04c7401a7cbef,
(gerrit change-id Ieea485c0ebdce9fb9c876cad005cb95fd8e0c899)
with minor changes for changing include paths and building script.

Change-Id: I77b94fe69b20f04c338e7be7387125f709fa9e1a
Refs: #3018
2015-07-22 10:56:21 -07:00
Joao Pereira 4bd28fc839 ci: build ndn-cxx as shared library
refs #2968

Change-Id: Idfa87a34f71c84b66686ed7afd954e6ba1fec9ba
2015-07-08 20:00:22 -07:00
Shock Jiang 0f0bc4b5b2 wscript: build a subset of tools
refs: #2670

Change-Id: I85951dd7510e36b48a630eb96e28f3351a3dac4f
2015-07-09 10:17:52 +08:00
121 changed files with 14094 additions and 352 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ if has OSX $NODE_LABELS; then
set -x
brew update
brew upgrade
brew install boost pkg-config
brew install boost pkg-config cryptopp
brew cleanup
fi
+12 -1
View File
@@ -2,12 +2,17 @@
set -x
set -e
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
source "$JDIR"/util.sh
pushd /tmp >/dev/null
INSTALLED_VERSION=$((cd ndn-cxx && git rev-parse HEAD) 2>/dev/null || echo NONE)
sudo rm -Rf ndn-cxx-latest
git clone --depth 1 git://github.com/named-data/ndn-cxx ndn-cxx-latest
LATEST_VERSION=$((cd ndn-cxx-latest && git rev-parse HEAD) 2>/dev/null || echo UNKNOWN)
if [[ $INSTALLED_VERSION != $LATEST_VERSION ]]; then
@@ -23,9 +28,15 @@ sudo rm -f /usr/local/lib/pkgconfig/libndn-cxx*
pushd ndn-cxx >/dev/null
./waf configure -j1 --color=yes --without-osx-keychain
./waf configure -j1 --color=yes --enable-shared --disable-static --without-osx-keychain
./waf -j1 --color=yes
sudo ./waf install -j1 --color=yes
popd >/dev/null
popd >/dev/null
if has Linux $NODE_LABELS; then
sudo ldconfig
elif has FreeBSD $NODE_LABELS; then
sudo ldconfig -a
fi
+7 -4
View File
@@ -5,12 +5,15 @@ os:
- osx
compiler:
- gcc
branches:
only:
- master
- clang
matrix:
exclude:
- os: linux
compiler: clang
- os: osx
compiler: gcc
script:
- if [[ $TRAVIS_OS_NAME == linux ]]; then export NODE_LABELS="Linux Ubuntu Ubuntu-12.04"; fi
- if [[ $TRAVIS_OS_NAME == osx ]]; then export NODE_LABELS="OSX OSX-10.10"; fi
- echo $NODE_LABELS
- ./.jenkins
+57 -21
View File
@@ -14,22 +14,21 @@ def configure(conf):
flags = ClangFlags()
else:
flags = CompilerFlags()
Logs.warn('The code has not been yet tested with %s compiler' % cxx)
Logs.warn('The code has not yet been tested with %s compiler' % cxx)
areCustomCxxflagsPresent = (len(conf.env.CXXFLAGS) > 0)
# General flags will alway be applied (e.g., selecting C++11 mode)
# General flags are always applied (e.g., selecting C++11 mode)
generalFlags = flags.getGeneralFlags(conf)
conf.add_supported_cxxflags(generalFlags['CXXFLAGS'])
conf.add_supported_linkflags(generalFlags['LINKFLAGS'])
conf.env.DEFINES += generalFlags['DEFINES']
# Debug or optimization CXXFLAGS and LINKFLAGS will be applied only if the
# Debug or optimized CXXFLAGS and LINKFLAGS are applied only if the
# corresponding environment variables are not set.
# DEFINES will be always applied
# DEFINES are always applied.
if conf.options.debug:
extraFlags = flags.getDebugFlags(conf)
if areCustomCxxflagsPresent:
missingFlags = [x for x in extraFlags['CXXFLAGS'] if x not in conf.env.CXXFLAGS]
if len(missingFlags) > 0:
@@ -41,7 +40,7 @@ def configure(conf):
if not areCustomCxxflagsPresent:
conf.add_supported_cxxflags(extraFlags['CXXFLAGS'])
conf.add_supported_cxxflags(extraFlags['LINKFLAGS'])
conf.add_supported_linkflags(extraFlags['LINKFLAGS'])
conf.env.DEFINES += extraFlags['DEFINES']
@@ -84,32 +83,43 @@ def add_supported_linkflags(self, linkflags):
class CompilerFlags(object):
def getGeneralFlags(self, conf):
"""Get dict {'CXXFLAGS':[...], LINKFLAGS:[...], DEFINES:[...]} that are always needed"""
"""Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are always needed"""
return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': []}
def getDebugFlags(self, conf):
"""Get tuple {CXXFLAGS, LINKFLAGS, DEFINES} that are needed in debug mode"""
"""Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are needed only in debug mode"""
return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': ['_DEBUG']}
def getOptimizedFlags(self, conf):
"""Get tuple {CXXFLAGS, LINKFLAGS, DEFINES} that are needed in optimized mode"""
"""Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are needed only in optimized mode"""
return {'CXXFLAGS': [], 'LINKFLAGS': [], 'DEFINES': ['NDEBUG']}
class GccBasicFlags(CompilerFlags):
"""This class defines base flags that work for gcc and clang compiler"""
"""
This class defines basic flags that work for both gcc and clang compilers
"""
def getDebugFlags(self, conf):
flags = super(GccBasicFlags, self).getDebugFlags(conf)
flags['CXXFLAGS'] += ['-pedantic', '-Wall',
'-O0',
flags['CXXFLAGS'] += ['-O0',
'-g3',
'-pedantic',
'-Wall',
'-Wextra',
'-Werror',
'-Wno-unused-parameter',
'-Wno-error=maybe-uninitialized', # Bug #1615
]
]
return flags
def getOptimizedFlags(self, conf):
flags = super(GccBasicFlags, self).getOptimizedFlags(conf)
flags['CXXFLAGS'] += ['-pedantic', '-Wall', '-O2', '-g']
flags['CXXFLAGS'] += ['-O2',
'-g',
'-pedantic',
'-Wall',
'-Wextra',
'-Wno-unused-parameter',
]
return flags
class GccFlags(GccBasicFlags):
@@ -130,24 +140,50 @@ class GccFlags(GccBasicFlags):
def getDebugFlags(self, conf):
flags = super(GccFlags, self).getDebugFlags(conf)
version = tuple(int(i) for i in conf.env['CC_VERSION'])
if version < (5, 1, 0):
flags['CXXFLAGS'] += ['-Wno-missing-field-initializers']
flags['CXXFLAGS'] += ['-Og', # gcc >= 4.8
'-fdiagnostics-color', # gcc >= 4.9
]
]
return flags
def getOptimizedFlags(self, conf):
flags = super(GccFlags, self).getOptimizedFlags(conf)
version = tuple(int(i) for i in conf.env['CC_VERSION'])
if version < (5, 1, 0):
flags['CXXFLAGS'] += ['-Wno-missing-field-initializers']
flags['CXXFLAGS'] += ['-fdiagnostics-color'] # gcc >= 4.9
return flags
class ClangFlags(GccBasicFlags):
def getGeneralFlags(self, conf):
flags = super(ClangFlags, self).getGeneralFlags(conf)
flags['CXXFLAGS'] += ['-std=c++11',
'-Wno-error=unneeded-internal-declaration', # Bug #1588
'-Wno-error=deprecated-register',
]
if Utils.unversioned_sys_platform() == "darwin":
flags['CXXFLAGS'] += ['-std=c++11']
if Utils.unversioned_sys_platform() == 'darwin':
flags['CXXFLAGS'] += ['-stdlib=libc++']
flags['LINKFLAGS'] += ['-stdlib=libc++']
return flags
def getDebugFlags(self, conf):
flags = super(ClangFlags, self).getDebugFlags(conf)
flags['CXXFLAGS'] += ['-fcolor-diagnostics']
version = tuple(int(i) for i in conf.env['CC_VERSION'])
if Utils.unversioned_sys_platform() == 'darwin' and version < (7, 0, 0):
flags['CXXFLAGS'] += ['-Wno-missing-field-initializers']
flags['CXXFLAGS'] += ['-fcolor-diagnostics',
'-Wno-unused-local-typedef', # Bugs #2657 and #3209
'-Wno-error=unneeded-internal-declaration', # Bug #1588
'-Wno-error=deprecated-register',
'-Wno-error=keyword-macro', # Bug #3235
]
return flags
def getOptimizedFlags(self, conf):
flags = super(ClangFlags, self).getOptimizedFlags(conf)
version = tuple(int(i) for i in conf.env['CC_VERSION'])
if Utils.unversioned_sys_platform() == 'darwin' and version < (7, 0, 0):
flags['CXXFLAGS'] += ['-Wno-missing-field-initializers']
flags['CXXFLAGS'] += ['-fcolor-diagnostics',
'-Wno-unused-local-typedef', # Bugs #2657 and #3209
]
return flags
+9
View File
@@ -11,3 +11,12 @@ in ndn-tools:
* Davide Pesavento <http://www.lip6.fr/actualite/personnes-fiche.php?ident=D1469>
* Junxiao Shi <http://www.cs.arizona.edu/people/shijunxiao/>
* Eric Newberry <http://ericnewberry.com/>
* Xiaoke Jiang <http://netarchlab.tsinghua.edu.cn/~shock/>
* Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
* Qi Zhao <https://www.linkedin.com/pub/qi-zhao/73/835/9a3>
* Seunghyun Yoo <http://relue2718.com/>
* Seungbae Kim <https://sites.google.com/site/sbkimcv/>
* Wentao Shang <http://irl.cs.ucla.edu/~wentao/>
* Steve DiBenedetto <https://dibenede.github.io>
* Andrea Tosatto <https://linkedin.com/in/tosattoandrea>
* Vince Lehman <http://vslehman.com>
+4
View File
@@ -6,9 +6,13 @@ These tools are recommended to be installed on all NDN nodes.
Tools in this collection include:
* [peek](tools/peek): transmit a single packet between a consumer and a producer
* [chunks](tools/chunks): segmented file transfer between a consumer and producer
* [ping](tools/ping): test reachability between two nodes
* [dump](tools/dump): analyze traffic on wire
* [dissect](tools/dissect): inspect TLV structure of NDN packet format
* [dissect-wireshark](tools/dissect-wireshark): Wireshark extension to inspect TLV structure of NDN
packets
* [pib](tools/pib): a service to manage the public information of keys and publish certificates
See [INSTALL.md](INSTALL.md) for build instructions.
+3 -1
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -63,7 +63,9 @@
#include <ndn-cxx/security/key-chain.hpp>
#include <ndn-cxx/security/signing-helpers.hpp>
#include <ndn-cxx/security/signing-info.hpp>
#include <ndn-cxx/util/backports.hpp>
#include <ndn-cxx/util/scheduler.hpp>
#include <ndn-cxx/util/scheduler-scoped-event-id.hpp>
#include <ndn-cxx/util/signal.hpp>
namespace ndn {
+1 -1
View File
@@ -22,7 +22,7 @@
namespace ndn {
namespace tools {
const char VERSION[] = "0.1.0-dev";
const char VERSION[] = "0.2";
} // namespace tools
} // namespace ndn
+1
View File
@@ -12,4 +12,5 @@ man_pages = [
('ndnpingserver', 'ndnpingserver', 'reachability testing server', None, 1),
('ndndump', 'ndndump', 'traffic analysis tool', None, 8),
('ndn-dissect', 'ndn-dissect', 'NDN packet format inspector', None, 1),
('ndn-pib', 'ndn-pib', 'NDN PIB service', None, 1),
]
+35
View File
@@ -0,0 +1,35 @@
ndn-pib
========
``ndn-pib`` is a public key and certificate management and publishing service.
Usage
-----
::
ndn-pib [-h] -o owner -d database_dir -t tpm_locator
Description
-----------
This command will start a PIB service process which serves signing key lookup/management for local
applications and also public the public key certificate of signing keys. The lookup/management
interface listens on a prefix "/localhost/pib/[OwnerName]" and accept five types of command (get,
default, list, update, delete). More details can be found at `Public key Info Base (PIB) Service
<http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base>`__
Since PIB service is queried through Interest/Data exchange, NFD is required to run before this
command is executed.
This command requires three arguments: ``owner`` specify the owner of the pib service, which is also
the third name component in the local lookup/management prefix; ``database_dir`` is the path to the
database where all the public key, certificate, identity are stored and managed; ``tpm_locator`` is
locator of a TPM which stores the corresponding private key of the public keys in PIB.
Example
-------
::
$ ndn-pib -o alice -d /var/pib -t tpm-file:/var/ndn/tpm
+5 -5
View File
@@ -11,16 +11,16 @@ Usage
Description
-----------
:program:`ndndump` is a traffic analysis tool that captures Interest and Data packets on the wire,
and displays brief information about captured packets.
:program:`ndndump` is a traffic analysis tool that captures Interest, Data, and Nack packets on the
wire and displays brief information about captured packets.
Currently, :program:`ndndump` is capable of extracting Interest and Data packets from:
Currently, :program:`ndndump` is capable of extracting Interest, Data, and Nack packets from:
* Ethernet, when bare Interest/Data is transmitted without NDNLP header
* Ethernet
* PPP link (e.g., pcap trace from ndnSIM)
* IPv4 UDP unicast tunnel
* IPv4 UDP multicast group
* IPv6 TCP tunnel, when Interest/Data is aligned to the front of a TCP segment
* IPv4 TCP tunnel, when Interest/Data/Nack is aligned to the front of a TCP segment
Options
-------
+31 -10
View File
@@ -6,7 +6,7 @@ Usage
::
ndnpeek [-h] [-f] [-r] [-m min] [-M max] [-l lifetime] [-p] [-w timeout] name
ndnpeek [-h] [-f] [-r] [-m min] [-M max] [-l lifetime] [-p] [-w timeout] [-v] [-V] name
Description
-----------
@@ -21,30 +21,51 @@ occurs.
Options
-------
``-h``
Print help and exit
``-h, --help``
Print help and exit.
``-f``
``-f, --fresh``
If specified, set ``MustBeFresh`` selector in the Interest packet.
``-r``
``-r, --rightmost``
Set ``ChildSelector=1`` (the rightmost child) selector.
``-m``
``-m, --minsuffix min``
Set ``min`` as the ``MinSuffixComponents`` selector.
``-M``
``-M, --maxsuffix max``
Set ``max`` as the ``MaxSuffixComponents`` selector.
``-l``
``-l, --lifetime lifetime``
Set ``lifetime`` (in milliseconds) as the ``InterestLifetime``.
``-p``
``-p, --payload``
If specified, print the received payload only, not the full packet.
``-w``
``-w, --timeout timeout``
Timeout after ``timeout`` milliseconds.
``-v, --verbose``
If specified, verbose output.
``-V, --version``
Print version and exit.
``--link-file [file]``
Read Link object from ``file`` and add it to the expressed Interest.
Exit Codes
----------
0: Success
1: An unspecified error occurred
2: Malformed command line
3: Network operation timed out
4: Nack received
Examples
--------
+142
View File
@@ -0,0 +1,142 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Andrea Tosatto
*/
#include "tools/chunks/catchunks/consumer.hpp"
#include "tests/test-common.hpp"
#include <ndn-cxx/util/dummy-client-face.hpp>
#include <ndn-cxx/security/validator-null.hpp>
#include <boost/test/output_test_stream.hpp>
namespace ndn {
namespace chunks {
namespace tests {
using namespace ndn::tests;
using boost::test_tools::output_test_stream;
BOOST_AUTO_TEST_SUITE(Chunks)
BOOST_AUTO_TEST_SUITE(TestConsumer)
BOOST_AUTO_TEST_CASE(OutputDataSequential)
{
// Test sequential segments in the right order
// Segment order: 0 1 2
std::string name("/ndn/chunks/test");
std::vector<std::string> testStrings {
"",
"a1b2c3%^&(#$&%^$$/><",
"123456789123456789123456789123456789123456789123456789123456789"
"123456789123456789123456789123456789123456789123456789123456789",
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. "
"Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur "
"ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla "
"consequat massa Donec pede justo,"
};
util::DummyClientFace face;
ValidatorNull validator;
output_test_stream output("");
Consumer cons(face, validator, false, output);
auto interest = makeInterest(name);
for (size_t i = 0; i < testStrings.size(); ++i) {
output.flush();
auto data = makeData(Name(name).appendVersion(1).appendSegment(i));
data->setContent(reinterpret_cast<const uint8_t*>(testStrings[i].data()),
testStrings[i].size());
cons.m_bufferedData[i] = data;
cons.writeInOrderData();
BOOST_CHECK(output.is_equal(testStrings[i]));
}
}
BOOST_AUTO_TEST_CASE(OutputDataUnordered)
{
// Test unordered segments
// Segment order: 1 0 2
std::string name("/ndn/chunks/test");
std::vector<std::string> testStrings {
"a1b2c3%^&(#$&%^$$/><",
"123456789123456789123456789123456789123456789123456789123456789"
"123456789123456789123456789123456789123456789123456789123456789",
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. "
"Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur "
"ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla "
"consequat massa Donec pede justo,"
};;
util::DummyClientFace face;
ValidatorNull validator;
output_test_stream output("");
Consumer cons(face, validator, false, output);
auto interest = makeInterest(name);
std::vector<shared_ptr<Data>> dataStore;
for (size_t i = 0; i < testStrings.size(); ++i) {
auto data = makeData(Name(name).appendVersion(1).appendSegment(i));
data->setContent(reinterpret_cast<const uint8_t*>(testStrings[i].data()),
testStrings[i].size());
dataStore.push_back(data);
}
output.flush();
cons.m_bufferedData[1] = dataStore[1];
cons.writeInOrderData();
BOOST_CHECK(output.is_equal(""));
output.flush();
cons.m_bufferedData[0] = dataStore[0];
cons.writeInOrderData();
BOOST_CHECK(output.is_equal(testStrings[0] + testStrings[1]));
output.flush();
cons.m_bufferedData[2] = dataStore[2];
cons.writeInOrderData();
BOOST_CHECK(output.is_equal(testStrings[2]));
}
BOOST_AUTO_TEST_SUITE_END() // TestConsumer
BOOST_AUTO_TEST_SUITE_END() // Chunks
} // namespace tests
} // namespace chunks
} // namespace ndn
+147
View File
@@ -0,0 +1,147 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Andrea Tosatto
*/
#include "tools/chunks/catchunks/discover-version-fixed.hpp"
#include "discover-version-fixture.hpp"
namespace ndn {
namespace chunks {
namespace tests {
using namespace ndn::tests;
class DiscoverVersionFixedFixture : public DiscoverVersionFixture
{
public:
DiscoverVersionFixedFixture()
: DiscoverVersionFixture(makeOptions())
, version(1449227841747)
{
setDiscover(make_unique<DiscoverVersionFixed>(Name(name).appendVersion(version),
face, makeOptions()));
}
protected:
uint64_t version; //Version to find
};
BOOST_AUTO_TEST_SUITE(Chunks)
BOOST_AUTO_TEST_SUITE(TestDiscoverVersionFixed)
BOOST_FIXTURE_TEST_CASE(RequestedVersionAvailable, DiscoverVersionFixedFixture)
{
discover->run();
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
face.receive(*makeDataWithVersion(version));
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
BOOST_CHECK_EQUAL(discoveredVersion, version);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
auto lastInterest = face.sentInterests.back();
BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
BOOST_CHECK_EQUAL(lastInterest.getMaxSuffixComponents(), 2);
BOOST_CHECK_EQUAL(lastInterest.getMinSuffixComponents(), 2);
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
}
BOOST_FIXTURE_TEST_CASE(NoVersionsAvailable, DiscoverVersionFixedFixture)
{
discover->run();
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
for (int retries = 0; retries < maxRetriesOnTimeoutOrNack; ++retries) {
advanceClocks(io, interestLifetime, 1);
BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2 + retries);
}
for (const auto& lastInterest : face.sentInterests) {
BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
BOOST_CHECK_EQUAL(lastInterest.getMaxSuffixComponents(), 2);
BOOST_CHECK_EQUAL(lastInterest.getMinSuffixComponents(), 2);
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
BOOST_CHECK_EQUAL(lastInterest.getName().equals(Name(name).appendVersion(version)), true);
}
advanceClocks(io, interestLifetime, 1);
BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
// check if discovered version is the default value
BOOST_CHECK_EQUAL(discoveredVersion, 0);
BOOST_CHECK_EQUAL(face.sentInterests.size(), maxRetriesOnTimeoutOrNack + 1);
}
BOOST_FIXTURE_TEST_CASE(DataNotSegment, DiscoverVersionFixedFixture)
{
discover->run();
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
std::vector<std::string> randomStrings {
"",
"abcdefg",
"12345",
"qr%67a3%4e"
};
Exclude expectedExclude;
for (size_t retries = 0; retries < randomStrings.size(); ++retries) {
auto data = make_shared<Data>(Name(name).appendVersion(version).append(randomStrings[retries]));
data->setFinalBlockId(name::Component::fromSegment(0));
data = signData(data);
face.receive(*data);
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1 + retries);
auto lastInterest = face.sentInterests.back();
if (randomStrings[retries] != "")
expectedExclude.excludeOne(name::Component::fromEscapedString(randomStrings[retries]));
BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
BOOST_CHECK_EQUAL(lastInterest.getMaxSuffixComponents(), 2);
BOOST_CHECK_EQUAL(lastInterest.getMinSuffixComponents(), 2);
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
}
advanceClocks(io, interestLifetime, maxRetriesOnTimeoutOrNack + 1);
BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
// check if discovered version is the default value
BOOST_CHECK_EQUAL(discoveredVersion, 0);
}
BOOST_AUTO_TEST_SUITE_END() // TestDiscoverVersionFixed
BOOST_AUTO_TEST_SUITE_END() // Chunks
} // namespace tests
} // namespace chunks
} // namespace ndn
+104
View File
@@ -0,0 +1,104 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Andrea Tosatto
*/
#ifndef NDN_TOOLS_TESTS_CHUNKS_DISCOVER_VERSION_FIXTURE_HPP
#define NDN_TOOLS_TESTS_CHUNKS_DISCOVER_VERSION_FIXTURE_HPP
#include "tools/chunks/catchunks/discover-version.hpp"
#include "tests/test-common.hpp"
#include <ndn-cxx/util/dummy-client-face.hpp>
namespace ndn {
namespace chunks {
namespace tests {
class DiscoverVersionFixture : public ndn::tests::UnitTestTimeFixture, virtual protected Options
{
public:
DiscoverVersionFixture(const Options& options)
: Options(options)
, face(io)
, name("/ndn/chunks/test")
, isDiscoveryFinished(false)
, discoveredVersion(0)
{
}
protected:
void setDiscover(unique_ptr<DiscoverVersion> disc)
{
discover = std::move(disc);
discover->onDiscoverySuccess.connect(bind(&DiscoverVersionFixture::onSuccess, this, _1));
discover->onDiscoveryFailure.connect(bind(&DiscoverVersionFixture::onFailure, this, _1));
}
shared_ptr<Data>
makeDataWithVersion(uint64_t version)
{
auto data = make_shared<Data>(Name(name).appendVersion(version).appendSegment(0));
data->setFinalBlockId(name::Component::fromSegment(0));
return ndn::tests::signData(data);
}
static Options
makeOptions()
{
Options options;
options.isVerbose = false;
options.interestLifetime = time::seconds(1);
options.maxRetriesOnTimeoutOrNack = 3;
return options;
}
virtual void
onSuccess(const Data& data)
{
isDiscoveryFinished = true;
if (data.getName()[name.size()].isVersion())
discoveredVersion = data.getName()[name.size()].toVersion();
}
virtual void
onFailure(const std::string& reason)
{
isDiscoveryFinished = true;
}
protected:
boost::asio::io_service io;
util::DummyClientFace face;
Name name;
unique_ptr<DiscoverVersion> discover;
bool isDiscoveryFinished;
uint64_t discoveredVersion;
};
} // namespace tests
} // namespace chunks
} // namespace ndn
#endif // NDN_TOOLS_TESTS_CHUNKS_DISCOVER_VERSION_FIXTURE_HPP
@@ -0,0 +1,235 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Andrea Tosatto
*/
#include "tools/chunks/catchunks/discover-version-iterative.hpp"
#include "discover-version-fixture.hpp"
namespace ndn {
namespace chunks {
namespace tests {
using namespace ndn::tests;
class DiscoverVersionIterativeFixture : public DiscoverVersionFixture,
protected DiscoverVersionIterativeOptions
{
public:
typedef DiscoverVersionIterativeOptions Options;
public:
explicit
DiscoverVersionIterativeFixture(const Options& opt = makeOptionsIterative())
: chunks::Options(opt)
, DiscoverVersionFixture(opt)
, Options(opt)
{
setDiscover(make_unique<DiscoverVersionIterative>(Name(name), face, opt));
}
protected:
static Options
makeOptionsIterative()
{
Options options;
options.isVerbose = false;
options.maxRetriesOnTimeoutOrNack = 3;
options.maxRetriesAfterVersionFound = 1;
return options;
}
};
BOOST_AUTO_TEST_SUITE(Chunks)
BOOST_AUTO_TEST_SUITE(TestDiscoverVersionIterative)
BOOST_FIXTURE_TEST_CASE(SingleVersionAvailable, DiscoverVersionIterativeFixture)
{
discover->run();
advanceClocks(io, time::nanoseconds(1), 1);
uint64_t version = 1449241767037;
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
auto lastInterest = face.sentInterests.back();
BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
// Send first segment for the right version
face.receive(*makeDataWithVersion(version));
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2);
lastInterest = face.sentInterests.back();
Exclude expectedExclude;
expectedExclude.excludeBefore(name::Component::fromVersion(version));
BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
// Generate the timeout
for (int retries = 0; retries < maxRetriesAfterVersionFound; ++retries) {
advanceClocks(io, interestLifetime, 1);
BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), retries + 3);
lastInterest = face.sentInterests.back();
Exclude expectedExclude;
expectedExclude.excludeBefore(name::Component::fromVersion(version));
BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
}
advanceClocks(io, interestLifetime, 1);
BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
BOOST_CHECK_EQUAL(discoveredVersion, version);
BOOST_CHECK_EQUAL(face.sentInterests.size(), maxRetriesAfterVersionFound + 2);
}
BOOST_FIXTURE_TEST_CASE(NoVersionsAvailable, DiscoverVersionIterativeFixture)
{
discover->run();
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
for (int retries = 0; retries < maxRetriesOnTimeoutOrNack; ++retries) {
advanceClocks(io, interestLifetime, 1);
BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2 + retries);
}
for (auto& lastInterest : face.sentInterests) {
BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
}
advanceClocks(io, interestLifetime, 1);
BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
BOOST_CHECK_EQUAL(face.sentInterests.size(), maxRetriesOnTimeoutOrNack + 1);
}
BOOST_FIXTURE_TEST_CASE(MultipleVersionsAvailable, DiscoverVersionIterativeFixture)
{
// nVersions must be positive
const uint64_t nVersions = 5;
discover->run();
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
auto lastInterest = face.sentInterests.back();
BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
for (uint64_t nSentVersions = 0; nSentVersions < nVersions; ++nSentVersions) {
face.receive(*makeDataWithVersion(nSentVersions));
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2 + nSentVersions);
lastInterest = face.sentInterests.back();
Exclude expectedExclude;
expectedExclude.excludeBefore(name::Component::fromVersion(nSentVersions));
BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
}
for (int retries = 0; retries < maxRetriesAfterVersionFound; ++retries) {
advanceClocks(io, interestLifetime, 1);
BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2 + retries + nVersions);
lastInterest = face.sentInterests.back();
Exclude expectedExclude;
expectedExclude.excludeBefore(name::Component::fromVersion(nVersions - 1));
BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
}
advanceClocks(io, interestLifetime, 1);
BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
BOOST_CHECK_EQUAL(discoveredVersion, nVersions - 1);
BOOST_CHECK_EQUAL(face.sentInterests.size(), nVersions + maxRetriesAfterVersionFound + 1);
}
BOOST_FIXTURE_TEST_CASE(MultipleVersionsAvailableDescendent, DiscoverVersionIterativeFixture)
{
// nVersions must be positive
const uint64_t nVersions = 5;
discover->run();
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
auto lastInterest = face.sentInterests.back();
BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
for (uint64_t nVersionsToSend = nVersions; nVersionsToSend > 0; --nVersionsToSend) {
face.receive(*makeDataWithVersion(nVersionsToSend - 1));
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2);
lastInterest = face.sentInterests.back();
Exclude expectedExclude;
expectedExclude.excludeBefore(name::Component::fromVersion(nVersions - 1));
BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
}
advanceClocks(io, interestLifetime, maxRetriesAfterVersionFound + 1);
BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
BOOST_CHECK_EQUAL(discoveredVersion, nVersions - 1);
BOOST_CHECK_EQUAL(face.sentInterests.size(), maxRetriesAfterVersionFound + 2);
}
BOOST_AUTO_TEST_SUITE_END() // TestDiscoverVersionIterative
BOOST_AUTO_TEST_SUITE_END() // Chunks
} // namespace tests
} // namespace chunks
} // namespace ndn
+378
View File
@@ -0,0 +1,378 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Andrea Tosatto
*/
#include "tools/chunks/catchunks/pipeline-interests.hpp"
#include "tools/chunks/catchunks/data-fetcher.hpp"
#include "tests/test-common.hpp"
#include <ndn-cxx/util/dummy-client-face.hpp>
namespace ndn {
namespace chunks {
namespace tests {
using namespace ndn::tests;
class PipelineInterestsFixture : public UnitTestTimeFixture
{
public:
typedef PipelineInterestsOptions Options;
public:
PipelineInterestsFixture()
: face(io)
, opt(makeOptions())
, name("/ndn/chunks/test")
, pipeline(face, opt)
, nDataSegments(0)
, nReceivedSegments(0)
, hasFailed(false)
{
}
protected:
shared_ptr<Data>
makeDataWithSegment(uint64_t segmentNo, bool setFinalBlockId = true)
{
auto data = make_shared<Data>(Name(name).appendVersion(0).appendSegment(segmentNo));
if (setFinalBlockId)
data->setFinalBlockId(name::Component::fromSegment(nDataSegments - 1));
return signData(data);
}
void
runWithData(const Data& data)
{
pipeline.runWithExcludedSegment(data,
bind(&PipelineInterestsFixture::onData, this, _1, _2),
bind(&PipelineInterestsFixture::onFailure, this, _1));
}
private:
void
onData(const Interest& interest, const Data& data)
{
nReceivedSegments++;
}
void
onFailure(const std::string& reason)
{
hasFailed = true;
}
static Options
makeOptions()
{
Options options;
options.isVerbose = false;
options.interestLifetime = time::seconds(1);
options.maxRetriesOnTimeoutOrNack = 3;
options.maxPipelineSize = 5;
return options;
}
protected:
boost::asio::io_service io;
util::DummyClientFace face;
Options opt;
Name name;
PipelineInterests pipeline;
uint64_t nDataSegments;
uint64_t nReceivedSegments;
bool hasFailed;
};
BOOST_AUTO_TEST_SUITE(Chunks)
BOOST_AUTO_TEST_SUITE(TestPipelineInterests)
BOOST_FIXTURE_TEST_CASE(FewerSegmentsThanPipelineCapacity, PipelineInterestsFixture)
{
nDataSegments = 3;
BOOST_ASSERT(nDataSegments <= opt.maxPipelineSize);
runWithData(*makeDataWithSegment(0));
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), nDataSegments - 1);
for (uint64_t i = 0; i < nDataSegments - 1; ++i) {
face.receive(*makeDataWithSegment(i));
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_CHECK_EQUAL(nReceivedSegments, i);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), nDataSegments - 1);
// check if the interest for the segment i+1 is well formed
auto sentInterest = face.sentInterests[i];
BOOST_CHECK_EQUAL(sentInterest.getExclude().size(), 0);
BOOST_CHECK_EQUAL(sentInterest.getMaxSuffixComponents(), 1);
BOOST_CHECK_EQUAL(sentInterest.getMustBeFresh(), opt.mustBeFresh);
BOOST_CHECK_EQUAL(Name(name).isPrefixOf(sentInterest.getName()), true);
BOOST_CHECK_EQUAL(sentInterest.getName()[-1].toSegment(), i + 1);
}
BOOST_CHECK_EQUAL(hasFailed, false);
advanceClocks(io, ndn::DEFAULT_INTEREST_LIFETIME, opt.maxRetriesOnTimeoutOrNack + 1);
BOOST_CHECK_EQUAL(hasFailed, true);
}
BOOST_FIXTURE_TEST_CASE(FullPipeline, PipelineInterestsFixture)
{
nDataSegments = 13;
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
runWithData(*makeDataWithSegment(nDataSegments - 1));
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
for (uint64_t i = 0; i < nDataSegments - 1; ++i) {
face.receive(*makeDataWithSegment(i));
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_CHECK_EQUAL(nReceivedSegments, i + 1);
if (i < nDataSegments - opt.maxPipelineSize - 1) {
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize + i + 1);
// check if the interest for the segment i+1 is well formed
auto sentInterest = face.sentInterests[i];
BOOST_CHECK_EQUAL(sentInterest.getExclude().size(), 0);
BOOST_CHECK_EQUAL(sentInterest.getMaxSuffixComponents(), 1);
BOOST_CHECK_EQUAL(sentInterest.getMustBeFresh(), opt.mustBeFresh);
BOOST_CHECK_EQUAL(Name(name).isPrefixOf(sentInterest.getName()), true);
BOOST_CHECK_EQUAL(sentInterest.getName()[-1].toSegment(), i);
}
else {
// all the interests have been sent for all the segments
BOOST_CHECK_EQUAL(face.sentInterests.size(), nDataSegments - 1);
}
}
BOOST_CHECK_EQUAL(hasFailed, false);
}
BOOST_FIXTURE_TEST_CASE(TimeoutAllSegments, PipelineInterestsFixture)
{
nDataSegments = 13;
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
runWithData(*makeDataWithSegment(nDataSegments - 1));
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
for (int i = 0; i < opt.maxRetriesOnTimeoutOrNack; ++i) {
advanceClocks(io, opt.interestLifetime, 1);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * (i + 2));
BOOST_CHECK_EQUAL(nReceivedSegments, 0);
// A single retry for every pipeline element
for (size_t j = 0; j < opt.maxPipelineSize; ++j) {
auto interest = face.sentInterests[(opt.maxPipelineSize * (i + 1)) + j];
BOOST_CHECK_EQUAL(static_cast<size_t>(interest.getName()[-1].toSegment()), j);
}
}
advanceClocks(io, opt.interestLifetime, 1);
BOOST_CHECK_EQUAL(hasFailed, true);
}
BOOST_FIXTURE_TEST_CASE(TimeoutAfterFinalBlockIdReceived, PipelineInterestsFixture)
{
// the FinalBlockId is sent with the first segment, after the first segment failure the pipeline
// should fail
nDataSegments = 18;
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
runWithData(*makeDataWithSegment(nDataSegments - 1));
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
// send a single segment for each pipeline element but not the first element
advanceClocks(io, opt.interestLifetime, 1);
for (uint64_t i = 1; i < opt.maxPipelineSize; ++i) {
face.receive(*makeDataWithSegment(i));
advanceClocks(io, time::nanoseconds(1), 1);
}
// send a single data packet for each pipeline element
advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack - 1);
for (uint64_t i = 0; i < opt.maxPipelineSize - 1; ++i) {
face.receive(*makeDataWithSegment(opt.maxPipelineSize + i));
advanceClocks(io, time::nanoseconds(1), 1);
}
advanceClocks(io, opt.interestLifetime, 1);
size_t interestAfterFailure = face.sentInterests.size();
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
BOOST_CHECK_EQUAL(hasFailed, true);
// these new segments should not generate new interests
advanceClocks(io, opt.interestLifetime, 1);
for (uint64_t i = 0; i < opt.maxPipelineSize - 1; ++i) {
face.receive(*makeDataWithSegment(opt.maxPipelineSize * 2 + i - 1));
advanceClocks(io, time::nanoseconds(1), 1);
}
// no more interests after a failure
advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack);
BOOST_CHECK_EQUAL(interestAfterFailure, face.sentInterests.size());
BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
}
BOOST_FIXTURE_TEST_CASE(TimeoutBeforeFinalBlockIdReceived, PipelineInterestsFixture)
{
// the FinalBlockId is sent only with the last segment, all segments are sent except for the
// second one (segment #1); all segments are received correctly until the FinalBlockId is received
nDataSegments = 22;
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
runWithData(*makeDataWithSegment(nDataSegments - 1, false));
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
advanceClocks(io, opt.interestLifetime, 1);
for (uint64_t i = 2; i < opt.maxPipelineSize; ++i) {
face.receive(*makeDataWithSegment(i, false));
advanceClocks(io, time::nanoseconds(1), 1);
auto lastInterest = face.sentInterests.back();
BOOST_CHECK_EQUAL(lastInterest.getName()[-1].toSegment(), opt.maxPipelineSize + i - 2);
}
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * 3 - 2);
// nack for the first pipeline element (segment #0)
auto nack = make_shared<lp::Nack>(face.sentInterests[opt.maxPipelineSize]);
nack->setReason(lp::NackReason::DUPLICATE);
face.receive(*nack);
// all the pipeline elements are two retries near the timeout error, but not the
// second (segment #1) that is only one retry near the timeout
advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack - 1);
BOOST_CHECK_EQUAL(hasFailed, false);
// data for the first pipeline element (segment #0)
face.receive(*makeDataWithSegment(0, false));
BOOST_CHECK_EQUAL(hasFailed, false);
// data for all the pipeline element, but not the second (segment #1)
for (uint64_t i = opt.maxPipelineSize; i < nDataSegments - 1; ++i) {
if (i == nDataSegments - 2) {
face.receive(*makeDataWithSegment(i, true));
}
else {
face.receive(*makeDataWithSegment(i, false));
}
advanceClocks(io, time::nanoseconds(1), 1);
}
// timeout for the second pipeline element (segment #1), this should trigger an error
advanceClocks(io, opt.interestLifetime, 1);
BOOST_CHECK_EQUAL(nReceivedSegments, nDataSegments - 2);
BOOST_CHECK_EQUAL(hasFailed, true);
}
BOOST_FIXTURE_TEST_CASE(SegmentReceivedAfterTimeout, PipelineInterestsFixture)
{
// the FinalBlockId is never sent, all the pipeline elements with a segment number greater than
// segment #0 will fail, after this failure also segment #0 fail and this should trigger an error
nDataSegments = 22;
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
runWithData(*makeDataWithSegment(nDataSegments - 1, false));
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
advanceClocks(io, opt.interestLifetime, 1);
// nack for the first pipeline element (segment #0)
auto nack = make_shared<lp::Nack>(face.sentInterests[opt.maxPipelineSize]);
nack->setReason(lp::NackReason::DUPLICATE);
face.receive(*nack);
BOOST_CHECK_EQUAL(hasFailed, false);
// timeout for all the pipeline elements, but not the first (segment #0)
advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack);
BOOST_CHECK_EQUAL(hasFailed, false);
// data for the first pipeline element (segment #0), this should trigger an error because the
// others pipeline elements failed
face.receive(*makeDataWithSegment(0, false));
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_CHECK_EQUAL(nReceivedSegments, 1);
BOOST_CHECK_EQUAL(hasFailed, true);
}
BOOST_FIXTURE_TEST_CASE(CongestionAllSegments, PipelineInterestsFixture)
{
nDataSegments = 13;
BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
runWithData(*makeDataWithSegment(nDataSegments - 1));
advanceClocks(io, time::nanoseconds(1), 1);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
// send nack for all the pipeline elements first interest
for (size_t j = 0; j < opt.maxPipelineSize; j++) {
auto nack = make_shared<lp::Nack>(face.sentInterests[j]);
nack->setReason(lp::NackReason::CONGESTION);
face.receive(*nack);
advanceClocks(io, time::nanoseconds(1), 1);
}
// send nack for all the pipeline elements interests after the first
for (int i = 1; i <= opt.maxRetriesOnTimeoutOrNack; ++i) {
time::milliseconds backoffTime(static_cast<uint64_t>(std::pow(2, i)));
if (backoffTime > DataFetcher::MAX_CONGESTION_BACKOFF_TIME)
backoffTime = DataFetcher::MAX_CONGESTION_BACKOFF_TIME;
advanceClocks(io, backoffTime, 1);
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * (i +1));
// A single retry for every pipeline element
for (size_t j = 0; j < opt.maxPipelineSize; ++j) {
auto interest = face.sentInterests[(opt.maxPipelineSize * i) + j];
BOOST_CHECK_LT(static_cast<size_t>(interest.getName()[-1].toSegment()), opt.maxPipelineSize);
}
for (size_t j = 0; j < opt.maxPipelineSize; j++) {
auto nack = make_shared<lp::Nack>(face.sentInterests[(opt.maxPipelineSize * i) + j]);
nack->setReason(lp::NackReason::CONGESTION);
face.receive(*nack);
advanceClocks(io, time::nanoseconds(1), 1);
}
}
BOOST_CHECK_EQUAL(hasFailed, true);
}
BOOST_AUTO_TEST_SUITE_END() // TestPipelineInterests
BOOST_AUTO_TEST_SUITE_END() // Chunks
} // namespace tests
} // namespace chunks
} // namespace ndn
+233
View File
@@ -0,0 +1,233 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Andrea Tosatto
*/
#include "tools/chunks/putchunks/producer.hpp"
#include "tests/test-common.hpp"
#include <ndn-cxx/util/dummy-client-face.hpp>
#include <ndn-cxx/security/validator-null.hpp>
#include <cmath>
namespace ndn {
namespace chunks {
namespace tests {
using namespace ndn::tests;
BOOST_AUTO_TEST_SUITE(Chunks)
BOOST_AUTO_TEST_SUITE(TestProducer)
BOOST_AUTO_TEST_CASE(InputData)
{
util::DummyClientFace face;
KeyChain keyChain;
security::SigningInfo signingInfo;
Name prefix("/ndn/chunks/test");
int maxSegmentSize = 40;
std::vector<std::string> testStrings {
"",
"a1b2c3%^&(#$&%^$$/><",
"123456789123456789123456789123456789123456789123456789123456789"
"123456789123456789123456789123456789123456789123456789123456789",
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. "
"Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur "
"ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla "
"consequat massa Donec pede justo,"
};
for (size_t i = 0; i < testStrings.size(); ++i) {
std::istringstream str(testStrings[i]);
Producer prod(prefix, face, keyChain, signingInfo, time::seconds(4), maxSegmentSize, false,
false, str);
size_t expectedSize = std::ceil(static_cast<double>(testStrings[i].size()) / maxSegmentSize);
if (testStrings[i].size() == 0)
expectedSize = 1;
BOOST_CHECK_EQUAL(prod.m_store.size(), expectedSize);
}
}
BOOST_AUTO_TEST_CASE(RequestSegmentUnspecifiedVersion)
{
boost::asio::io_service io;
util::DummyClientFace face(io, {true, true});
KeyChain keyChain;
security::SigningInfo signingInfo;
Name prefix("/ndn/chunks/test");
time::milliseconds freshnessPeriod(time::seconds(10));
size_t maxSegmentSize(40);
std::istringstream testString(std::string(
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget "
"dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, "
"nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, "
"sem. Nulla consequat massa Donec pede justo,"));
Name keyLocatorName = keyChain.getDefaultCertificateName().getPrefix(-1);
Producer producer(prefix, face, keyChain, signingInfo, freshnessPeriod, maxSegmentSize,
false, false, testString);
io.poll();
size_t nSegments = std::ceil(static_cast<double>(testString.str().size()) / maxSegmentSize);
// version request
face.receive(*makeInterest(prefix));
face.processEvents();
BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
auto lastData = face.sentData.back();
BOOST_REQUIRE_EQUAL(lastData.getName().size(), prefix.size() + 2);
BOOST_CHECK_EQUAL(lastData.getName()[-1].toSegment(), 0);
BOOST_REQUIRE(!lastData.getFinalBlockId().empty());
BOOST_CHECK_EQUAL(lastData.getFinalBlockId().toSegment(), nSegments - 1);
BOOST_CHECK_EQUAL(lastData.getSignature().getKeyLocator().getName(), keyLocatorName);
// segment request
Name nameWithVersion(prefix);
nameWithVersion.append(lastData.getName()[-2]);
size_t requestSegmentNo = 1;
face.receive(*makeInterest(nameWithVersion.appendSegment(requestSegmentNo)));
face.processEvents();
BOOST_REQUIRE_EQUAL(face.sentData.size(), 2);
lastData = face.sentData.back();
BOOST_REQUIRE_EQUAL(lastData.getName().size(), prefix.size() + 2);
BOOST_CHECK_EQUAL(lastData.getName()[-1].toSegment(), requestSegmentNo);
BOOST_REQUIRE(!lastData.getFinalBlockId().empty());
BOOST_CHECK_EQUAL(lastData.getFinalBlockId().toSegment(), nSegments - 1);
BOOST_CHECK_EQUAL(lastData.getSignature().getKeyLocator().getName(), keyLocatorName);
}
BOOST_AUTO_TEST_CASE(RequestSegmentSpecifiedVersion)
{
boost::asio::io_service io;
util::DummyClientFace face(io, {true, true});
KeyChain keyChain;
security::SigningInfo signingInfo;
Name prefix("/ndn/chunks/test");
time::milliseconds freshnessPeriod(time::seconds(10));
size_t maxSegmentSize(40);
std::istringstream testString(std::string(
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget "
"dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, "
"nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, "
"sem. Nulla consequat massa Donec pede justo,"));
uint64_t version = 1449227841747;
Name keyLocatorName = keyChain.getDefaultCertificateName().getPrefix(-1);
Producer producer(prefix.appendVersion(version), face, keyChain, signingInfo, freshnessPeriod,
maxSegmentSize, false, false, testString);
io.poll();
size_t nSegments = std::ceil(static_cast<double>(testString.str().size()) / maxSegmentSize);
// version request
face.receive(*makeInterest(prefix));
face.processEvents();
BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
auto lastData = face.sentData.back();
BOOST_REQUIRE_EQUAL(lastData.getName().size(), prefix.size() + 1);
BOOST_CHECK_EQUAL(lastData.getName()[-2].toVersion(), version);
BOOST_CHECK_EQUAL(lastData.getName()[-1].toSegment(), 0);
BOOST_REQUIRE(!lastData.getFinalBlockId().empty());
BOOST_CHECK_EQUAL(lastData.getFinalBlockId().toSegment(), nSegments - 1);
BOOST_CHECK_EQUAL(lastData.getSignature().getKeyLocator().getName(), keyLocatorName);
// segment request
Name nameWithVersion(prefix);
size_t requestSegmentNo = 1;
face.receive(*makeInterest(nameWithVersion.appendSegment(requestSegmentNo)));
face.processEvents();
BOOST_REQUIRE_EQUAL(face.sentData.size(), 2);
lastData = face.sentData.back();
BOOST_REQUIRE_EQUAL(lastData.getName().size(), prefix.size() + 1);
BOOST_CHECK_EQUAL(lastData.getName()[-2].toVersion(), version);
BOOST_CHECK_EQUAL(lastData.getName()[-1].toSegment(), requestSegmentNo);
BOOST_REQUIRE(!lastData.getFinalBlockId().empty());
BOOST_CHECK_EQUAL(lastData.getFinalBlockId().toSegment(), nSegments - 1);
BOOST_CHECK_EQUAL(lastData.getSignature().getKeyLocator().getName(), keyLocatorName);
}
BOOST_AUTO_TEST_CASE(RequestNotExistingSegment)
{
boost::asio::io_service io;
util::DummyClientFace face(io, {true, true});
KeyChain keyChain;
security::SigningInfo signingInfo;
Name prefix("/ndn/chunks/test");
time::milliseconds freshnessPeriod(time::seconds(10));
size_t maxSegmentSize(40);
std::istringstream testString(std::string(
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget "
"dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, "
"nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, "
"sem. Nulla consequat massa Donec pede justo,"));
Name keyLocatorName = keyChain.getDefaultCertificateName().getPrefix(-1);
Producer producer(prefix, face, keyChain, signingInfo, freshnessPeriod, maxSegmentSize,
false, false, testString);
io.poll();
size_t nSegments = std::ceil(static_cast<double>(testString.str().size()) / maxSegmentSize);
// version request
face.receive(*makeInterest(prefix));
face.processEvents();
BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
auto lastData = face.sentData.back();
BOOST_REQUIRE_EQUAL(lastData.getName().size(), prefix.size() + 2);
BOOST_CHECK_EQUAL(lastData.getName()[-1].toSegment(), 0);
BOOST_REQUIRE(!lastData.getFinalBlockId().empty());
BOOST_CHECK_EQUAL(lastData.getFinalBlockId().toSegment(), nSegments - 1);
BOOST_CHECK_EQUAL(lastData.getSignature().getKeyLocator().getName(), keyLocatorName);
// segment request
Name nameWithVersion(prefix);
nameWithVersion.append(lastData.getName()[-2]);
face.receive(*makeInterest(nameWithVersion.appendSegment(nSegments)));
face.processEvents();
// no new data
BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
}
BOOST_AUTO_TEST_SUITE_END() // TestProducer
BOOST_AUTO_TEST_SUITE_END() // Chunks
} // namespace tests
} // namespace chunks
} // namespace ndn
+107
View File
@@ -0,0 +1,107 @@
Testing Instructions
====================
This folder contains several crafted tcpdump traces that can be used to manually check
correctness of NDN Packet Dissector for Wireshark in several scenarios.
To use the dissector, follow the instructions in
[dissector's README.md](../../tools/dissect-wireshark/README.md).
`-r <trace-file>` command-line flag can be used to directly open a specific trace file in
WireShark. For example:
wireshark -X lua_script:../../tools/dissect-wireshark/ndn.lua -r ipv4-udp-fragmented.pcap
## Test Cases / Trace File Description
### 1. IPv4 UDP
Trace file: `ipv4-udp-fragmented.pcap`
Trace summary: several IPv4 UDP packets, carrying NDN interests and data packets. One
datagram is fragmented into several IPv4 packets.
Expected result of the dissection:
- NDN interests are dissected from packets 1, 2, 3, and 8.
- NDN data packet is dissected from defragmented packets 4, 5, 6, and 7.
### 2. IPv6 UDP
Trace file: `ipv6-udp-fragmented.pcap`
Trace summary: several IPv6 UDP packets, carrying NDN interests and data packets. One
datagram is fragmented into several IPv6 packets.
Expected result of the dissection:
- NDN interests are dissected from packets 1, and 2.
- NDN data packet is dissected from defragmented packets 3, 4, 5, and 6.
### 3. IPv4 TCP
#### 3.1. De-segmentation and dissection
Trace file: `ipv4-tcp-segmented.pcap`
Trace summary: several IPv4 TCP packets, carrying NDN interest and a data packets. The data
packet spans several TCP segments.
Expected result of the dissection:
- interest packet is properly dissected from packet 2.
- data packet is properly dissected after de-segmentation of payloads in packets 4, 5, 6, and 7.
#### 3.2. Dissection of TCP segments containing multiple NDN packets
Trace file: `ipv4-tcp-multi-ndn-packets-in-segment.pcap`
Trace summary: Several IPv4 TCP packets, payload of one containing several NDN interests.
Expected result of the dissection:
- a single interest packet is dissected from packet 1.
- four interest packets are dissected from packet 3.
### 4. IPv6 TCP
Trace file: `ipv6-tcp-segmented.pcap`
Trace summary: several IPv6 TCP packets, carrying an NDN data packet that spans several
TCP segments.
Expected result of the dissection:
- data packet is properly dissected after de-segmentation of payloads in packets 2, 3, 4, and 5.
### 5. IPv4 TCP/WebSocket
Trace file: `ipv4-websocket-segmented.pcap`
Trace summary: Partial capture of a live IPv4 WebSocket session with a single NDN interest
retrieving large (~5k) NDN data packet.
Expected result of the dissection:
- interest packet is dissected after a partial reconstruction of WebSocket session at
packet 16.
- data packet is properly dissected after a partial reconstruction of WebSocket
conversation at packet 22.
### 6. IPv6 TCP/WebSocket
Trace file: `ipv6-websocket-segmented.pcap`
Trace summary: Partial capture of a live IPv6 WebSocket session with a single NDN interest
retrieving large (~5k) NDN data packet.
Expected result of the dissection:
- interest packet is dissected after a partial reconstruction of WebSocket session at
packet 6.
- data packet is properly dissected after a partial reconstruction of WebSocket
conversation at packet 12.
### 7. Ethernet
Trace file: `ethernet.pcap`
Trace summary: Short capture, containing an NDN interest multicasted directly in Ethernet frame.
Expected result of the dissection:
- interest packet is dissected from packet 6.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+29
View File
@@ -0,0 +1,29 @@
Testing Instructions
====================
This folder contains a tcpdump trace that can be used to manually check
the correctness of ndndump.
## Test Cases / Trace File Description
### 1. NDNLPv2 NACK
Trace file: `nack.pcap`
Trace summary: Six IPv4 UDP packets, carrying NDN interests and NACK packets.
Twelve IPv4 TCP packets, carrying NDN interests and NACK packets.
Expected result of the capture:
- 3 NDN interests are captured with UDP tunnel type.
- 3 NACKs are captured with UDP tunnel type and the NACK reasons:
- Congestion
- Duplicate
- None
- 3 NDN interests are captured with TCP tunnel type.
- 4 NACKs are captured with TCP tunnel type and the NACK reasons:
- Congestion
- Duplicate
- None
- None
Binary file not shown.
+247
View File
@@ -0,0 +1,247 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2016, University of Memphis.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "tools/dump/ndndump.hpp"
#include "tests/test-common.hpp"
#include <boost/test/output_test_stream.hpp>
#include <ndn-cxx/lp/packet.hpp>
#include <ndn-cxx/security/key-chain.hpp>
#include <ndn-cxx/util/ethernet.hpp>
namespace ndn {
namespace dump {
namespace tests {
using namespace ndn::tests;
class StdCoutRedirector
{
public:
StdCoutRedirector(std::ostream& os)
{
// Redirect std::cout to the specified output stream
originalBuffer = std::cout.rdbuf(os.rdbuf());
}
~StdCoutRedirector()
{
// Revert state for std::cout
std::cout.rdbuf(originalBuffer);
}
private:
std::streambuf* originalBuffer;
};
class NdnDumpFixture
{
protected:
NdnDumpFixture()
{
dump.m_dataLinkType = DLT_EN10MB;
}
template <typename Packet>
void
receive(const Packet& packet)
{
ndn::EncodingBuffer buffer(packet.wireEncode());
receive(buffer);
}
void
receive(ndn::EncodingBuffer& buffer)
{
ndn::util::ethernet::Address host;
// Ethernet header
uint16_t frameType = htons(ndn::util::ethernet::ETHERTYPE_NDN);
buffer.prependByteArray(reinterpret_cast<const uint8_t*>(&frameType),
ndn::util::ethernet::TYPE_LEN);
buffer.prependByteArray(host.data(), host.size());
buffer.prependByteArray(host.data(), host.size());
pcap_pkthdr header{};
header.len = buffer.size();
{
StdCoutRedirector redirect(output);
dump.onCapturedPacket(&header, buffer.buf());
}
}
protected:
Ndndump dump;
boost::test_tools::output_test_stream output;
};
BOOST_FIXTURE_TEST_SUITE(NdnDump, NdnDumpFixture)
BOOST_AUTO_TEST_CASE(CaptureInterest)
{
ndn::Interest interest("/test");
interest.setNonce(0);
this->receive(interest);
const std::string expectedOutput =
"0.000000 Tunnel Type: EthernetFrame, INTEREST: /test?ndn.Nonce=0\n";
BOOST_CHECK(output.is_equal(expectedOutput));
}
BOOST_AUTO_TEST_CASE(CaptureData)
{
ndn::security::KeyChain keyChain;
ndn::Data data("/test");
keyChain.sign(data);
this->receive(data);
const std::string expectedOutput = "0.000000 Tunnel Type: EthernetFrame, DATA: /test\n";
BOOST_CHECK(output.is_equal(expectedOutput));
}
BOOST_AUTO_TEST_CASE(CaptureNack)
{
ndn::Interest interest("/test");
interest.setNonce(0);
ndn::lp::Nack nack(interest);
nack.setReason(ndn::lp::NackReason::DUPLICATE);
lp::Packet lpPacket(interest.wireEncode());
lpPacket.add<lp::NackField>(nack.getHeader());
this->receive(lpPacket);
const std::string expectedOutput =
"0.000000 Tunnel Type: EthernetFrame, NACK: Duplicate, /test?ndn.Nonce=0\n";
BOOST_CHECK(output.is_equal(expectedOutput));
}
BOOST_AUTO_TEST_CASE(CaptureLpFragment)
{
const uint8_t data[10] = {
0x06, 0x08, // Data packet
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
};
ndn::Buffer buffer(data, 4);
lp::Packet lpPacket;
lpPacket.add<lp::FragmentField>(std::make_pair(buffer.begin(), buffer.end()));
lpPacket.add<lp::FragIndexField>(0);
lpPacket.add<lp::FragCountField>(2);
lpPacket.add<lp::SequenceField>(1000);
this->receive(lpPacket);
const std::string expectedOutput =
"0.000000 Tunnel Type: EthernetFrame, NDNLPv2-FRAGMENT\n";
BOOST_CHECK(output.is_equal(expectedOutput));
}
BOOST_AUTO_TEST_CASE(CaptureIdlePacket)
{
lp::Packet lpPacket;
this->receive(lpPacket);
const std::string expectedOutput =
"0.000000 Tunnel Type: EthernetFrame, NDNLPv2-IDLE\n";
BOOST_CHECK(output.is_equal(expectedOutput));
}
BOOST_AUTO_TEST_CASE(CaptureIncompletePacket)
{
const uint8_t interest[] = {
0x05, 0x0E, // Interest
0x07, 0x06, // Name
0x08, 0x04, // NameComponent
0x74, 0x65, 0x73, 0x74,
0x0a, 0x04, // Nonce
0x00, 0x00, 0x00, 0x01
};
EncodingBuffer buffer;
buffer.prependByteArray(interest, 4);
this->receive(buffer);
const std::string expectedOutput =
"0.000000 Tunnel Type: EthernetFrame, INCOMPLETE-PACKET, size: 4\n";
BOOST_CHECK(output.is_equal(expectedOutput));
}
BOOST_AUTO_TEST_CASE(CaptureUnknownNetworkPacket)
{
EncodingBuffer buffer(ndn::encoding::makeEmptyBlock(tlv::Name));
this->receive(buffer);
const std::string expectedOutput =
"0.000000 Tunnel Type: EthernetFrame, UNKNOWN-NETWORK-PACKET\n";
BOOST_CHECK(output.is_equal(expectedOutput));
}
BOOST_AUTO_TEST_CASE(DumpPcapTrace)
{
dump.inputFile = "tests/dump/nack.pcap";
dump.pcapProgram = "";
{
StdCoutRedirector redirect(output);
dump.run();
}
const std::string expectedOutput =
"1456768916.467099 From: 1.0.0.1, To: 1.0.0.2, Tunnel Type: UDP, INTEREST: /producer/nack/congestion?ndn.MustBeFresh=1&ndn.Nonce=2581361680\n"
"1456768916.567099 From: 1.0.0.1, To: 1.0.0.2, Tunnel Type: UDP, INTEREST: /producer/nack/duplicate?ndn.MustBeFresh=1&ndn.Nonce=4138343109\n"
"1456768916.667099 From: 1.0.0.1, To: 1.0.0.2, Tunnel Type: UDP, INTEREST: /producer/nack/no-reason?ndn.MustBeFresh=1&ndn.Nonce=4034910304\n"
"1456768916.767099 From: 1.0.0.2, To: 1.0.0.1, Tunnel Type: UDP, NACK: Congestion, /producer/nack/congestion?ndn.MustBeFresh=1&ndn.Nonce=2581361680\n"
"1456768916.867099 From: 1.0.0.2, To: 1.0.0.1, Tunnel Type: UDP, NACK: Duplicate, /producer/nack/duplicate?ndn.MustBeFresh=1&ndn.Nonce=4138343109\n"
"1456768916.967099 From: 1.0.0.2, To: 1.0.0.1, Tunnel Type: UDP, NACK: None, /producer/nack/no-reason?ndn.MustBeFresh=1&ndn.Nonce=4034910304\n"
"1456768917.067099 From: 1.0.0.1, To: 1.0.0.2, Tunnel Type: TCP, INTEREST: /producer/nack/congestion?ndn.MustBeFresh=1&ndn.Nonce=3192497423\n"
"1456768917.267099 From: 1.0.0.2, To: 1.0.0.1, Tunnel Type: TCP, NACK: Congestion, /producer/nack/congestion?ndn.MustBeFresh=1&ndn.Nonce=3192497423\n"
"1456768917.367099 From: 1.0.0.1, To: 1.0.0.2, Tunnel Type: TCP, INTEREST: /producer/nack/duplicate?ndn.MustBeFresh=1&ndn.Nonce=522390724\n"
"1456768917.567099 From: 1.0.0.2, To: 1.0.0.1, Tunnel Type: TCP, NACK: Duplicate, /producer/nack/duplicate?ndn.MustBeFresh=1&ndn.Nonce=522390724\n"
"1456768917.767099 From: 1.0.0.2, To: 1.0.0.1, Tunnel Type: TCP, NACK: None, /producer/nack/no-reason?ndn.MustBeFresh=1&ndn.Nonce=2002441365\n"
"1456768917.967099 From: 1.0.0.1, To: 1.0.0.2, Tunnel Type: TCP, INTEREST: /producer/nack/no-reason?ndn.MustBeFresh=1&ndn.Nonce=3776824408\n"
"1456768918.067099 From: 1.0.0.2, To: 1.0.0.1, Tunnel Type: TCP, NACK: None, /producer/nack/no-reason?ndn.MustBeFresh=1&ndn.Nonce=3776824408\n";
BOOST_CHECK(output.is_equal(expectedOutput));
}
BOOST_AUTO_TEST_SUITE_END()
} // namespace tests
} // namespace dump
} // namespace ndn
@@ -0,0 +1,58 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "identity-management-time-fixture.hpp"
namespace ndn {
namespace tests {
IdentityManagementTimeFixture::IdentityManagementTimeFixture()
: m_keyChainTmpPath(boost::filesystem::path(TMP_TESTS_PATH) / "PibIdMgmtTimeTest")
, m_keyChain(std::string("pib-sqlite3:").append(m_keyChainTmpPath.string()),
std::string("tpm-file:").append(m_keyChainTmpPath.string()))
{
}
IdentityManagementTimeFixture::~IdentityManagementTimeFixture()
{
for (const auto& identity : m_identities) {
m_keyChain.deleteIdentity(identity);
}
boost::filesystem::remove_all(m_keyChainTmpPath);
}
bool
IdentityManagementTimeFixture::addIdentity(const Name& identity, const KeyParams& params)
{
try {
m_keyChain.createIdentity(identity, params);
m_identities.push_back(identity);
return true;
}
catch (std::runtime_error&) {
return false;
}
}
} // namespace tests
} // namespace ndn
@@ -0,0 +1,61 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#ifndef NDN_TOOLS_TESTS_IDENTITY_MANAGEMENT_TIME_FIXTURE_HPP
#define NDN_TOOLS_TESTS_IDENTITY_MANAGEMENT_TIME_FIXTURE_HPP
#include <ndn-cxx/security/key-chain.hpp>
#include <vector>
#include <boost/filesystem.hpp>
#include "tests/test-common.hpp"
namespace ndn {
namespace tests {
/**
* @brief IdentityManagementTimeFixture is a test suite level fixture.
* Test cases in the suite can use this fixture to create identities.
* Identities added via addIdentity method are automatically deleted
* during test teardown.
*/
class IdentityManagementTimeFixture : public tests::UnitTestTimeFixture
{
public:
IdentityManagementTimeFixture();
~IdentityManagementTimeFixture();
/// @brief add identity, return true if succeed.
bool
addIdentity(const Name& identity, const KeyParams& params = KeyChain::DEFAULT_KEY_PARAMS);
protected:
boost::filesystem::path m_keyChainTmpPath;
KeyChain m_keyChain;
std::vector<Name> m_identities;
};
} // namespace tests
} // namespace ndn
#endif // NDN_TOOLS_TESTS_IDENTITY_MANAGEMENT_TIME_FIXTURE_HPP
+132
View File
@@ -0,0 +1,132 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "tools/pib/cert-publisher.hpp"
#include "../identity-management-time-fixture.hpp"
#include <ndn-cxx/util/dummy-client-face.hpp>
#include <boost/filesystem.hpp>
#include "tests/test-common.hpp"
namespace ndn {
namespace pib {
namespace tests {
class CertPublisherFixture : public ndn::tests::IdentityManagementTimeFixture
{
public:
CertPublisherFixture()
: tmpPath(boost::filesystem::path(TMP_TESTS_PATH) / "DbTest")
, db(tmpPath.c_str())
, face(util::makeDummyClientFace(io, {true, true}))
{
}
~CertPublisherFixture()
{
boost::filesystem::remove_all(tmpPath);
}
boost::asio::io_service io;
boost::filesystem::path tmpPath;
PibDb db;
shared_ptr<util::DummyClientFace> face;
};
BOOST_FIXTURE_TEST_SUITE(PibCertPublisher, CertPublisherFixture)
BOOST_AUTO_TEST_CASE(Basic)
{
// Initialize id1
Name id1("/test/identity");
addIdentity(id1);
Name certName111 = m_keyChain.getDefaultCertificateNameForIdentity(id1);
shared_ptr<IdentityCertificate> cert111 = m_keyChain.getCertificate(certName111);
Name keyName11 = cert111->getPublicKeyName();
advanceClocks(io, time::milliseconds(100));
shared_ptr<IdentityCertificate> cert112 = m_keyChain.selfSign(keyName11);
Name certName112 = cert112->getName();
CertPublisher certPublisher(*face, db);
// Add a certificate
db.addCertificate(*cert111);
advanceClocks(io, time::milliseconds(2), 50);
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0);
auto interest111 = make_shared<Interest>(cert111->getName().getPrefix(-1));
face->receive(*interest111);
advanceClocks(io, time::milliseconds(2), 50);
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1);
BOOST_CHECK(face->sentDatas[0].wireEncode() == cert111->wireEncode());
face->sentDatas.clear();
// Add another certificate
db.addCertificate(*cert112);
advanceClocks(io, time::milliseconds(2), 50);
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0);
auto interest112 = make_shared<Interest>(cert112->getName().getPrefix(-1));
face->receive(*interest112);
advanceClocks(io, time::milliseconds(2), 50);
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1);
BOOST_CHECK(face->sentDatas[0].wireEncode() == cert111->wireEncode());
face->sentDatas.clear();
Exclude exclude;
exclude.excludeOne(cert111->getName().get(-1));
interest112->setExclude(exclude);
face->receive(*interest112);
advanceClocks(io, time::milliseconds(2), 50);
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1);
BOOST_CHECK(face->sentDatas[0].wireEncode() == cert112->wireEncode());
face->sentDatas.clear();
// delete a certificate
db.deleteCertificate(certName112);
face->receive(*interest112);
advanceClocks(io, time::milliseconds(2), 50);
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0);
face->receive(*interest111);
advanceClocks(io, time::milliseconds(2), 50);
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 1);
BOOST_CHECK(face->sentDatas[0].wireEncode() == cert111->wireEncode());
face->sentDatas.clear();
// delete another certificate
db.deleteCertificate(certName111);
face->receive(*interest112);
advanceClocks(io, time::milliseconds(2), 50);
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0);
face->receive(*interest111);
advanceClocks(io, time::milliseconds(2), 50);
BOOST_REQUIRE_EQUAL(face->sentDatas.size(), 0);
}
BOOST_AUTO_TEST_SUITE_END()
} // namespace tests
} // namespace pib
} // namespace ndn
+75
View File
@@ -0,0 +1,75 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "tools/pib/key-cache.hpp"
#include "tests/test-common.hpp"
namespace ndn {
namespace pib {
namespace tests {
BOOST_AUTO_TEST_SUITE(PibKeyCache)
BOOST_AUTO_TEST_CASE(Basic)
{
KeyCache keyCache(3);
Name name1("/1");
Name name2("/2");
Name name3("/3");
Name name4("/4");
auto key1 = make_shared<PublicKey>();
auto key2 = make_shared<PublicKey>();
auto key3 = make_shared<PublicKey>();
auto key4 = make_shared<PublicKey>();
keyCache.insert(name1, key1);
keyCache.insert(name2, key2);
keyCache.insert(name3, key3);
BOOST_CHECK_EQUAL(keyCache.size(), 3);
BOOST_CHECK(static_cast<bool>(keyCache.find(name1)));
BOOST_CHECK(static_cast<bool>(keyCache.find(name2)));
BOOST_CHECK(static_cast<bool>(keyCache.find(name3)));
BOOST_CHECK(!static_cast<bool>(keyCache.find(name4)));
keyCache.insert(name1, key1);
keyCache.insert(name4, key4);
BOOST_CHECK_EQUAL(keyCache.size(), 3);
BOOST_CHECK(static_cast<bool>(keyCache.find(name1)));
BOOST_CHECK(!static_cast<bool>(keyCache.find(name2)));
BOOST_CHECK(static_cast<bool>(keyCache.find(name3)));
BOOST_CHECK(static_cast<bool>(keyCache.find(name4)));
keyCache.erase(name1);
BOOST_CHECK_EQUAL(keyCache.size(), 2);
BOOST_CHECK(!static_cast<bool>(keyCache.find(name1)));
BOOST_CHECK(static_cast<bool>(keyCache.find(name3)));
BOOST_CHECK(static_cast<bool>(keyCache.find(name4)));
}
BOOST_AUTO_TEST_SUITE_END()
} // namespace tests
} // namespace pib
} // namespace ndn
+474
View File
@@ -0,0 +1,474 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "tools/pib/pib-db.hpp"
#include "../identity-management-time-fixture.hpp"
#include <boost/filesystem.hpp>
#include "tests/test-common.hpp"
namespace ndn {
namespace pib {
namespace tests {
class PibDbTestFixture : public ndn::tests::IdentityManagementTimeFixture
{
public:
PibDbTestFixture()
: tmpPath(boost::filesystem::path(TMP_TESTS_PATH) / "DbTest")
, db(tmpPath.c_str())
{
}
~PibDbTestFixture()
{
boost::filesystem::remove_all(tmpPath);
}
boost::asio::io_service io;
boost::filesystem::path tmpPath;
PibDb db;
std::vector<Name> deletedIds;
std::vector<Name> deletedKeys;
std::vector<Name> deletedCerts;
std::vector<Name> insertedCerts;
};
BOOST_FIXTURE_TEST_SUITE(PibPibDb, PibDbTestFixture)
BOOST_AUTO_TEST_CASE(MgmtTest)
{
Name testUser("/localhost/pib/test/mgmt");
addIdentity(testUser);
Name testUserCertName = m_keyChain.getDefaultCertificateNameForIdentity(testUser);
shared_ptr<IdentityCertificate> testUserCert = m_keyChain.getCertificate(testUserCertName);
BOOST_CHECK_EQUAL(db.getOwnerName(), "");
BOOST_CHECK(db.getMgmtCertificate() == nullptr);
db.updateMgmtCertificate(*testUserCert);
BOOST_CHECK_EQUAL(db.getOwnerName(), "test");
BOOST_REQUIRE(db.getMgmtCertificate() != nullptr);
BOOST_CHECK_EQUAL(db.getMgmtCertificate()->getName(), testUserCertName);
db.setTpmLocator("tpmLocator");
BOOST_CHECK_EQUAL(db.getTpmLocator(), "tpmLocator");
Name testUser2("/localhost/pib/test2/mgmt");
addIdentity(testUser2);
Name testUser2CertName = m_keyChain.getDefaultCertificateNameForIdentity(testUser2);
shared_ptr<IdentityCertificate> testUser2Cert = m_keyChain.getCertificate(testUser2CertName);
BOOST_CHECK_THROW(db.updateMgmtCertificate(*testUser2Cert), PibDb::Error);
Name testUserKeyName2 = m_keyChain.generateRsaKeyPairAsDefault(testUser);
shared_ptr<IdentityCertificate> testUserCert2 = m_keyChain.selfSign(testUserKeyName2);
BOOST_CHECK_NO_THROW(db.updateMgmtCertificate(*testUserCert2));
BOOST_REQUIRE(db.getMgmtCertificate() != nullptr);
BOOST_CHECK_EQUAL(db.getMgmtCertificate()->getName(),
testUserCert2->getName());
}
BOOST_AUTO_TEST_CASE(IdentityTest)
{
db.identityDeleted.connect([this] (const Name& id) {
this->deletedIds.push_back(id);
});
Name identity("/test/identity");
Name identity2("/test/identity2");
// Add an identity: /test/identity
// Since there is no default identity,
// the new added identity will be set as the default identity.
BOOST_CHECK_EQUAL(db.getDefaultIdentity(), PibDb::NON_EXISTING_IDENTITY);
db.addIdentity(identity);
BOOST_CHECK(db.hasIdentity(identity));
BOOST_CHECK_EQUAL(db.getDefaultIdentity(), identity);
// Add the second identity: /test/identity2
// Since the default identity exists,
// the new added identity will not be set as the default identity.
db.addIdentity(identity2);
BOOST_CHECK_EQUAL(db.hasIdentity(identity2), true);
BOOST_CHECK_EQUAL(db.getDefaultIdentity(), identity);
// Set the second identity: /test/identity2 as default explicitly
db.setDefaultIdentity(identity2);
BOOST_CHECK_EQUAL(db.getDefaultIdentity(), identity2);
// Delete identity /test/identity2, which is also the default one
// This will trigger the identityDeleted signal
// and also causes no default identity.
db.deleteIdentity(identity2);
BOOST_CHECK_EQUAL(db.hasIdentity(identity2), false);
BOOST_CHECK_EQUAL(db.hasIdentity(identity), true);
BOOST_CHECK_EQUAL(deletedIds.size(), 1);
BOOST_CHECK_EQUAL(deletedIds[0], identity2);
BOOST_CHECK_EQUAL(db.getDefaultIdentity(), PibDb::NON_EXISTING_IDENTITY);
deletedIds.clear();
// Add the second identity back
// Since there is no default identity (though another identity still exists),
// the second identity will be set as default.
db.addIdentity(identity2);
BOOST_CHECK_EQUAL(db.hasIdentity(identity2), true);
BOOST_CHECK_EQUAL(db.getDefaultIdentity(), identity2);
// Delete identity /test/identity
db.deleteIdentity(identity);
BOOST_CHECK_EQUAL(db.hasIdentity(identity), false);
BOOST_CHECK_EQUAL(db.hasIdentity(identity2), true);
BOOST_CHECK_EQUAL(deletedIds.size(), 1);
BOOST_CHECK_EQUAL(deletedIds[0], identity);
deletedIds.clear();
// Delete identity /test/identity2
db.deleteIdentity(identity2);
BOOST_CHECK_EQUAL(db.hasIdentity(identity), false);
BOOST_CHECK_EQUAL(db.hasIdentity(identity2), false);
BOOST_CHECK_EQUAL(deletedIds.size(), 1);
BOOST_CHECK_EQUAL(deletedIds[0], identity2);
deletedIds.clear();
}
BOOST_AUTO_TEST_CASE(KeyTest)
{
db.identityDeleted.connect([this] (const Name& id) {
this->deletedIds.push_back(id);
});
db.keyDeleted.connect([this] (const Name& key) {
this->deletedKeys.push_back(key);
});
// Initialize id1
Name id1("/test/identity");
addIdentity(id1);
Name certName111 = m_keyChain.getDefaultCertificateNameForIdentity(id1);
shared_ptr<IdentityCertificate> cert111 = m_keyChain.getCertificate(certName111);
Name keyName11 = cert111->getPublicKeyName();
PublicKey& key11 = cert111->getPublicKeyInfo();
advanceClocks(io, time::milliseconds(100));
Name keyName12 = m_keyChain.generateRsaKeyPairAsDefault(id1);
shared_ptr<IdentityCertificate> cert121 = m_keyChain.selfSign(keyName12);
PublicKey& key12 = cert121->getPublicKeyInfo();
// Initialize id2
advanceClocks(io, time::milliseconds(100));
Name id2("/test/identity2");
addIdentity(id2);
Name certName211 = m_keyChain.getDefaultCertificateNameForIdentity(id2);
shared_ptr<IdentityCertificate> cert211 = m_keyChain.getCertificate(certName211);
Name keyName21 = cert211->getPublicKeyName();
PublicKey& key21 = cert211->getPublicKeyInfo();
advanceClocks(io, time::milliseconds(100));
Name keyName22 = m_keyChain.generateRsaKeyPairAsDefault(id2);
shared_ptr<IdentityCertificate> cert221 = m_keyChain.selfSign(keyName22);
PublicKey& key22 = cert221->getPublicKeyInfo();
// Add a key, the corresponding identity should be added as well
// Since the PIB does not have any default identity set before,
// the added identity will be set as default.
// Since there is no default key for the identity,
// the added key will be set as default.
BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), PibDb::NON_EXISTING_KEY);
BOOST_CHECK(db.getKey(keyName11) == nullptr);
db.addKey(keyName11, key11);
BOOST_CHECK(db.hasIdentity(id1));
BOOST_CHECK(db.getKey(keyName11) != nullptr);
BOOST_CHECK_EQUAL(db.getDefaultIdentity(), id1);
BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), keyName11);
// Add the second key of /test/identity.
// Since the default key of /test/identity has been set,
// The new added key will not be set as default.
db.addKey(keyName12, key12);
BOOST_CHECK(db.getKey(keyName12) != nullptr);
BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), keyName11);
// Explicitly set the second key as the default key of /test/identity
db.setDefaultKeyNameOfIdentity(keyName12);
BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), keyName12);
// Delete the second key which is also the default key.
// This will trigger the keyDeleted signal.
// This will also cause no default key for /test/identity
db.deleteKey(keyName12);
BOOST_CHECK_EQUAL(db.hasKey(keyName12), false);
BOOST_CHECK_EQUAL(db.hasKey(keyName11), true);
BOOST_CHECK_EQUAL(db.hasKey(keyName22), false);
BOOST_CHECK_EQUAL(db.hasKey(keyName21), false);
BOOST_CHECK_EQUAL(deletedKeys.size(), 1);
BOOST_CHECK_EQUAL(deletedKeys[0], keyName12);
deletedKeys.clear();
// Add the second key back.
// Since there is no default key of /test/identity (although another key still exists)
// The second key will be set as the default key of /test/identity
BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), PibDb::NON_EXISTING_KEY);
db.addKey(keyName12, key12);
BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), keyName12);
// Prepare test for identity deletion
db.addKey(keyName21, key21);
db.addKey(keyName22, key22);
BOOST_CHECK_EQUAL(db.hasKey(keyName12), true);
BOOST_CHECK_EQUAL(db.hasKey(keyName22), true);
BOOST_CHECK_EQUAL(db.hasKey(keyName21), true);
BOOST_CHECK_EQUAL(db.hasIdentity(id2), true);
// Delete the identity.
// All keys of the identity should also be deleted,
// and the keyDeleted signal should be triggered twice.
db.deleteIdentity(id1);
BOOST_CHECK_EQUAL(db.hasIdentity(id1), false);
BOOST_CHECK_EQUAL(db.hasIdentity(id2), true);
BOOST_CHECK_EQUAL(db.hasKey(keyName11), false);
BOOST_CHECK_EQUAL(db.hasKey(keyName12), false);
BOOST_CHECK_EQUAL(db.hasKey(keyName21), true);
BOOST_CHECK_EQUAL(db.hasKey(keyName22), true);
BOOST_CHECK_EQUAL(deletedKeys.size(), 2);
BOOST_CHECK(std::find(deletedKeys.begin(), deletedKeys.end(), keyName11) !=
deletedKeys.end());
BOOST_CHECK(std::find(deletedKeys.begin(), deletedKeys.end(), keyName12) !=
deletedKeys.end());
BOOST_CHECK_EQUAL(deletedIds.size(), 1);
BOOST_CHECK_EQUAL(deletedIds[0], id1);
}
BOOST_AUTO_TEST_CASE(CertTest)
{
db.identityDeleted.connect([this] (const Name& id) {
this->deletedIds.push_back(id);
});
db.keyDeleted.connect([this] (const Name& key) {
this->deletedKeys.push_back(key);
});
db.certificateDeleted.connect([this] (const Name& certificate) {
this->deletedCerts.push_back(certificate);
});
db.certificateInserted.connect([this] (const Name& certificate) {
this->insertedCerts.push_back(certificate);
});
// Initialize id1
Name id1("/test/identity");
addIdentity(id1);
Name certName111 = m_keyChain.getDefaultCertificateNameForIdentity(id1);
shared_ptr<IdentityCertificate> cert111 = m_keyChain.getCertificate(certName111);
Name keyName11 = cert111->getPublicKeyName();
advanceClocks(io, time::milliseconds(100));
shared_ptr<IdentityCertificate> cert112 = m_keyChain.selfSign(keyName11);
Name certName112 = cert112->getName();
advanceClocks(io, time::milliseconds(100));
Name keyName12 = m_keyChain.generateRsaKeyPairAsDefault(id1);
shared_ptr<IdentityCertificate> cert121 = m_keyChain.selfSign(keyName12);
Name certName121 = cert121->getName();
advanceClocks(io, time::milliseconds(100));
shared_ptr<IdentityCertificate> cert122 = m_keyChain.selfSign(keyName12);
Name certName122 = cert122->getName();
// Initialize id2
advanceClocks(io, time::milliseconds(100));
Name id2("/test/identity2");
addIdentity(id2);
Name certName211 = m_keyChain.getDefaultCertificateNameForIdentity(id2);
shared_ptr<IdentityCertificate> cert211 = m_keyChain.getCertificate(certName211);
Name keyName21 = cert211->getPublicKeyName();
advanceClocks(io, time::milliseconds(100));
shared_ptr<IdentityCertificate> cert212 = m_keyChain.selfSign(keyName21);
Name certName212 = cert212->getName();
advanceClocks(io, time::milliseconds(100));
Name keyName22 = m_keyChain.generateRsaKeyPairAsDefault(id2);
shared_ptr<IdentityCertificate> cert221 = m_keyChain.selfSign(keyName22);
Name certName221 = cert221->getName();
advanceClocks(io, time::milliseconds(100));
shared_ptr<IdentityCertificate> cert222 = m_keyChain.selfSign(keyName22);
Name certName222 = cert222->getName();
// Add a certificate
// This will also add the corresponding key and identity.
// Since there is no default setting before,
// The certificate will be set as the default one of the key, and so be the key and identity
BOOST_CHECK_EQUAL(db.hasCertificate(certName111), false);
BOOST_CHECK_EQUAL(db.hasKey(keyName11), false);
BOOST_CHECK_EQUAL(db.hasIdentity(id1), false);
BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), PibDb::NON_EXISTING_CERTIFICATE);
db.addCertificate(*cert111);
BOOST_CHECK_EQUAL(db.hasCertificate(certName111), true);
BOOST_CHECK_EQUAL(db.hasKey(keyName11), true);
BOOST_CHECK_EQUAL(db.hasIdentity(id1), true);
BOOST_CHECK_EQUAL(db.getDefaultIdentity(), id1);
BOOST_CHECK_EQUAL(db.getDefaultKeyNameOfIdentity(id1), keyName11);
BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), certName111);
BOOST_CHECK_EQUAL(insertedCerts.size(), 1);
BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName111) !=
insertedCerts.end());
insertedCerts.clear();
// Add the second certificate of the same key
// Since default certificate already exists, no default setting changes.
BOOST_CHECK(db.getCertificate(certName112) == nullptr);
db.addCertificate(*cert112);
BOOST_CHECK(db.getCertificate(certName112) != nullptr);
BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), certName111);
BOOST_CHECK_EQUAL(insertedCerts.size(), 1);
BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName112) !=
insertedCerts.end());
insertedCerts.clear();
// Explicitly set the second certificate as the default one of the key.
db.setDefaultCertNameOfKey(certName112);
BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), certName112);
// Delete the default certificate
// This will trigger certificateDeleted signal
// and also causes no default certificate for the key.
db.deleteCertificate(certName112);
BOOST_CHECK_EQUAL(db.hasCertificate(certName112), false);
BOOST_CHECK_EQUAL(db.hasCertificate(certName111), true);
BOOST_CHECK_EQUAL(deletedCerts.size(), 1);
BOOST_CHECK_EQUAL(deletedCerts[0], certName112);
BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), PibDb::NON_EXISTING_CERTIFICATE);
deletedCerts.clear();
// Add the second certificate back
// Since there is no default certificate of the key (though another certificate still exists),
// the new added certificate will be set as default
db.addCertificate(*cert112);
BOOST_CHECK(db.getCertificate(certName112) != nullptr);
BOOST_CHECK_EQUAL(db.getDefaultCertNameOfKey(keyName11), certName112);
insertedCerts.clear();
// Add entries for delete tests
db.addCertificate(*cert111); // already exists no certInserted signal emitted
db.addCertificate(*cert112); // already exists no certInserted signal emitted
db.addCertificate(*cert121);
db.addCertificate(*cert122);
db.addCertificate(*cert211);
db.addCertificate(*cert212);
db.addCertificate(*cert221);
db.addCertificate(*cert222);
BOOST_CHECK_EQUAL(insertedCerts.size(), 6);
BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName121) !=
insertedCerts.end());
BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName122) !=
insertedCerts.end());
BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName211) !=
insertedCerts.end());
BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName212) !=
insertedCerts.end());
BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName221) !=
insertedCerts.end());
BOOST_CHECK(std::find(insertedCerts.begin(), insertedCerts.end(), certName222) !=
insertedCerts.end());
insertedCerts.clear();
// Delete the key.
// All the related certificates will be deleted as well.
db.deleteKey(keyName11);
BOOST_CHECK_EQUAL(db.hasCertificate(certName112), false);
BOOST_CHECK_EQUAL(db.hasCertificate(certName111), false);
BOOST_CHECK_EQUAL(db.hasCertificate(certName122), true);
BOOST_CHECK_EQUAL(db.hasCertificate(certName121), true);
BOOST_CHECK_EQUAL(db.hasCertificate(certName212), true);
BOOST_CHECK_EQUAL(db.hasCertificate(certName211), true);
BOOST_CHECK_EQUAL(db.hasCertificate(certName222), true);
BOOST_CHECK_EQUAL(db.hasCertificate(certName221), true);
BOOST_CHECK_EQUAL(db.hasKey(keyName11), false);
BOOST_CHECK_EQUAL(db.hasKey(keyName12), true);
BOOST_CHECK_EQUAL(db.hasKey(keyName21), true);
BOOST_CHECK_EQUAL(db.hasKey(keyName22), true);
BOOST_CHECK_EQUAL(deletedCerts.size(), 2);
BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName111) !=
deletedCerts.end());
BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName112) !=
deletedCerts.end());
BOOST_CHECK_EQUAL(deletedKeys.size(), 1);
BOOST_CHECK_EQUAL(deletedKeys[0], keyName11);
deletedCerts.clear();
deletedKeys.clear();
// Recover deleted entries
db.addCertificate(*cert111);
db.addCertificate(*cert112);
// Delete the identity
// All the related certificates and keys will be deleted as well.
BOOST_CHECK_EQUAL(db.hasCertificate(certName111), true);
BOOST_CHECK_EQUAL(db.hasCertificate(certName112), true);
BOOST_CHECK_EQUAL(db.hasKey(keyName11), true);
BOOST_CHECK_EQUAL(db.hasIdentity(id1), true);
db.deleteIdentity(id1);
BOOST_CHECK_EQUAL(db.hasCertificate(certName112), false);
BOOST_CHECK_EQUAL(db.hasCertificate(certName111), false);
BOOST_CHECK_EQUAL(db.hasCertificate(certName122), false);
BOOST_CHECK_EQUAL(db.hasCertificate(certName121), false);
BOOST_CHECK_EQUAL(db.hasCertificate(certName212), true);
BOOST_CHECK_EQUAL(db.hasCertificate(certName211), true);
BOOST_CHECK_EQUAL(db.hasCertificate(certName222), true);
BOOST_CHECK_EQUAL(db.hasCertificate(certName221), true);
BOOST_CHECK_EQUAL(db.hasKey(keyName11), false);
BOOST_CHECK_EQUAL(db.hasKey(keyName12), false);
BOOST_CHECK_EQUAL(db.hasKey(keyName21), true);
BOOST_CHECK_EQUAL(db.hasKey(keyName22), true);
BOOST_CHECK_EQUAL(db.hasIdentity(id1), false);
BOOST_CHECK_EQUAL(db.hasIdentity(id2), true);
BOOST_CHECK_EQUAL(deletedCerts.size(), 4);
BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName111) !=
deletedCerts.end());
BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName112) !=
deletedCerts.end());
BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName121) !=
deletedCerts.end());
BOOST_CHECK(std::find(deletedCerts.begin(), deletedCerts.end(), certName122) !=
deletedCerts.end());
BOOST_CHECK_EQUAL(deletedKeys.size(), 2);
BOOST_CHECK(std::find(deletedKeys.begin(), deletedKeys.end(), keyName11) !=
deletedKeys.end());
BOOST_CHECK(std::find(deletedKeys.begin(), deletedKeys.end(), keyName12) !=
deletedCerts.end());
BOOST_CHECK_EQUAL(deletedIds.size(), 1);
BOOST_CHECK_EQUAL(deletedIds[0], id1);
}
BOOST_AUTO_TEST_SUITE_END()
} // namespace tests
} // namespace pib
} // namespace ndn
+137
View File
@@ -0,0 +1,137 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "tools/pib/pib-validator.hpp"
#include "tools/pib/encoding/update-param.hpp"
#include "tools/pib/encoding/delete-param.hpp"
#include <ndn-cxx/security/key-chain.hpp>
#include "../identity-management-time-fixture.hpp"
#include <boost/filesystem.hpp>
#include "tests/test-common.hpp"
namespace ndn {
namespace pib {
namespace tests {
class PibValidatorFixture : public ndn::tests::IdentityManagementTimeFixture
{
public:
PibValidatorFixture()
: tmpPath(boost::filesystem::path(TMP_TESTS_PATH) / "DbTest")
, db(tmpPath.c_str())
{
}
~PibValidatorFixture()
{
boost::filesystem::remove_all(tmpPath);
}
boost::asio::io_service io;
boost::filesystem::path tmpPath;
PibDb db;
bool isProcessed;
};
BOOST_FIXTURE_TEST_SUITE(PibPibValidator, PibValidatorFixture)
BOOST_AUTO_TEST_CASE(Basic)
{
PibValidator validator(db);
Name testUser("/localhost/pib/test/mgmt");
BOOST_REQUIRE(addIdentity(testUser, RsaKeyParams()));
Name testUserCertName = m_keyChain.getDefaultCertificateNameForIdentity(testUser);
shared_ptr<IdentityCertificate> testUserCert = m_keyChain.getCertificate(testUserCertName);
advanceClocks(io, time::milliseconds(100));
Name testUser2("/localhost/pib/test2/mgmt");
BOOST_REQUIRE(addIdentity(testUser2, RsaKeyParams()));
db.updateMgmtCertificate(*testUserCert);
advanceClocks(io, time::milliseconds(100));
Name normalId("/normal/id");
BOOST_REQUIRE(addIdentity(normalId, RsaKeyParams()));
Name normalIdCertName = m_keyChain.getDefaultCertificateNameForIdentity(normalId);
shared_ptr<IdentityCertificate> normalIdCert = m_keyChain.getCertificate(normalIdCertName);
db.addIdentity(normalId);
db.addKey(normalIdCert->getPublicKeyName(), normalIdCert->getPublicKeyInfo());
db.addCertificate(*normalIdCert);
Name command1("/localhost/pib/test/verb/param");
shared_ptr<Interest> interest1 = make_shared<Interest>(command1);
m_keyChain.signByIdentity(*interest1, testUser);
// "test" user is trusted for any command about itself, OK.
isProcessed = false;
validator.validate(*interest1,
[this] (const shared_ptr<const Interest>&) {
isProcessed = true;
BOOST_CHECK(true);
},
[this] (const shared_ptr<const Interest>&, const std::string&) {
isProcessed = true;
BOOST_CHECK(false);
});
BOOST_CHECK(isProcessed);
Name command2("/localhost/pib/test/verb/param");
shared_ptr<Interest> interest2 = make_shared<Interest>(command2);
m_keyChain.signByIdentity(*interest2, testUser2);
// "test2" user is NOT trusted for any command about other user, MUST fail
isProcessed = false;
validator.validate(*interest2,
[this] (const shared_ptr<const Interest>&) {
isProcessed = true;
BOOST_CHECK(false);
},
[this] (const shared_ptr<const Interest>&, const std::string&) {
isProcessed = true;
BOOST_CHECK(true);
});
BOOST_CHECK(isProcessed);
Name command3("/localhost/pib/test/verb/param");
shared_ptr<Interest> interest3 = make_shared<Interest>(command3);
m_keyChain.signByIdentity(*interest3, normalId);
// "normalId" is in "test" pib, can be trusted for some commands about "test".
// Detail checking is needed, but it is not the job of Validator, OK.
isProcessed = false;
validator.validate(*interest3,
[this] (const shared_ptr<const Interest>&) {
isProcessed = true;
BOOST_CHECK(true);
},
[this] (const shared_ptr<const Interest>&, const std::string&) {
isProcessed = true;
BOOST_CHECK(false);
});
BOOST_CHECK(isProcessed);
}
BOOST_AUTO_TEST_SUITE_END()
} // namespace tests
} // namespace pib
} // namespace ndn
+1389
View File
File diff suppressed because it is too large Load Diff
+64
View File
@@ -0,0 +1,64 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "tools/pib/response-cache.hpp"
#include "tests/test-common.hpp"
namespace ndn {
namespace pib {
namespace tests {
BOOST_AUTO_TEST_SUITE(PibResponseCache)
BOOST_AUTO_TEST_CASE(Basic)
{
ResponseCache cache;
Name dataName("/test/data");
dataName.appendVersion();
shared_ptr<Data> data = make_shared<Data>(dataName);
Name dataNameNoVersion("/test/data");
Name anotherDataName("/test/another");
BOOST_CHECK_EQUAL(static_cast<bool>(cache.find(dataNameNoVersion)), false);
BOOST_CHECK_EQUAL(static_cast<bool>(cache.find(dataName, true)), false);
cache.insert(*data);
BOOST_CHECK(static_cast<bool>(cache.find(dataNameNoVersion)));
BOOST_CHECK(static_cast<bool>(cache.find(dataName, true)));
BOOST_CHECK_EQUAL(static_cast<bool>(cache.find(anotherDataName)), false);
BOOST_CHECK_EQUAL(static_cast<bool>(cache.find(anotherDataName, true)), false);
cache.erase(dataNameNoVersion);
BOOST_CHECK_EQUAL(static_cast<bool>(cache.find(dataNameNoVersion)), false);
BOOST_CHECK_EQUAL(static_cast<bool>(cache.find(dataName, true)), false);
}
BOOST_AUTO_TEST_SUITE_END()
} // namespace tests
} // namespace pib
} // namespace ndn
+121
View File
@@ -0,0 +1,121 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Arizona Board of Regents.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "tools/ping/client/ping.hpp"
#include <ndn-cxx/util/dummy-client-face.hpp>
#include "tests/test-common.hpp"
namespace ndn {
namespace ping {
namespace client {
namespace tests {
using namespace ndn::tests;
BOOST_AUTO_TEST_SUITE(PingClientPing)
class SequenceNumberIncrementFixture : public UnitTestTimeFixture
{
protected:
SequenceNumberIncrementFixture()
: face(util::makeDummyClientFace(io, {false, true}))
, pingOptions(makeOptions())
, ping(*face, pingOptions)
, numPings(0)
, lastPingSeq(pingOptions.startSeq)
{
ping.afterResponse.connect(bind(&SequenceNumberIncrementFixture::onResponse, this, _1));
ping.afterTimeout.connect(bind(&SequenceNumberIncrementFixture::onTimeout, this, _1));
}
public:
void
onResponse(uint64_t seq)
{
numPings++;
lastPingSeq = seq;
if (numPings == maxPings) {
face->shutdown();
io.stop();
}
}
void
onTimeout(uint64_t seq)
{
numPings++;
lastPingSeq = seq;
if (numPings == maxPings) {
face->shutdown();
io.stop();
}
}
private:
static Options
makeOptions()
{
Options opt;
opt.prefix = "ndn:/test-prefix";
opt.shouldAllowStaleData = false;
opt.shouldGenerateRandomSeq = false;
opt.shouldPrintTimestamp = false;
opt.nPings = 4;
opt.interval = time::milliseconds(100);
opt.timeout = time::milliseconds(1000);
opt.startSeq = 1000;
return opt;
}
protected:
boost::asio::io_service io;
shared_ptr<util::DummyClientFace> face;
Options pingOptions;
Ping ping;
uint32_t numPings;
uint32_t maxPings;
uint64_t lastPingSeq;
KeyChain keyChain;
};
BOOST_FIXTURE_TEST_CASE(SequenceNumberIncrement, SequenceNumberIncrementFixture)
{
maxPings = 4;
ping.start();
this->advanceClocks(io, time::milliseconds(1), 400);
face->receive(*makeData("ndn:/test-prefix/ping/1000"));
face->receive(*makeData("ndn:/test-prefix/ping/1001"));
face->receive(*makeData("ndn:/test-prefix/ping/1002"));
face->receive(*makeData("ndn:/test-prefix/ping/1003"));
io.run();
BOOST_REQUIRE_EQUAL(1003, lastPingSeq);
BOOST_REQUIRE_EQUAL(4, numPings);
}
BOOST_AUTO_TEST_SUITE_END()
} // namespace tests
} // namespace client
} // namespace ping
} // namespace ndn
+162
View File
@@ -0,0 +1,162 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Arizona Board of Regents.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "tools/ping/server/ping-server.hpp"
#include "tools/ping/client/ping.hpp"
#include <ndn-cxx/util/dummy-client-face.hpp>
#include "tests/test-common.hpp"
#include "../identity-management-time-fixture.hpp"
namespace ndn {
namespace ping {
namespace tests {
using namespace ndn::tests;
class PingIntegratedFixture : public IdentityManagementTimeFixture
{
public:
PingIntegratedFixture()
: serverFace(util::makeDummyClientFace(io, {false, true}))
, clientFace(util::makeDummyClientFace(io, {false, true}))
, numResponses(0)
, wantLoss(false)
{
serverFace->onSendInterest.connect([this] (const Interest& interest) {
io.post([=] { if (!wantLoss) { clientFace->receive(interest); } });
});
clientFace->onSendInterest.connect([this] (const Interest& interest) {
io.post([=] { if (!wantLoss) { serverFace->receive(interest); } });
});
serverFace->onSendData.connect([this] (const Data& data) {
io.post([=] { if (!wantLoss) { clientFace->receive(data); } });
});
clientFace->onSendData.connect([this] (const Data& data) {
io.post([=] { if (!wantLoss) { serverFace->receive(data); } });
});
}
void onTimeout(uint64_t seq)
{
numResponses++;
if (numResponses == maxResponses) {
serverFace->shutdown();
clientFace->shutdown();
io.stop();
}
}
void onData(uint64_t seq)
{
numResponses++;
if (numResponses == maxResponses) {
serverFace->shutdown();
clientFace->shutdown();
io.stop();
}
}
public:
boost::asio::io_service io;
shared_ptr<util::DummyClientFace> serverFace;
shared_ptr<util::DummyClientFace> clientFace;
std::unique_ptr<server::PingServer> server;
std::unique_ptr<client::Ping> client;
int maxResponses;
int numResponses;
bool wantLoss;
};
BOOST_AUTO_TEST_SUITE(PingIntegrated)
BOOST_FIXTURE_TEST_CASE(Normal, PingIntegratedFixture)
{
server::Options serverOpts;
serverOpts.prefix = "ndn:/test-prefix";
serverOpts.freshnessPeriod = time::milliseconds(5000);
serverOpts.nMaxPings = 4;
serverOpts.shouldPrintTimestamp = false;
serverOpts.payloadSize = 0;
server.reset(new server::PingServer(*serverFace, m_keyChain, serverOpts));
BOOST_REQUIRE_EQUAL(0, server->getNPings());
server->start();
client::Options clientOpts;
clientOpts.prefix = "ndn:/test-prefix";
clientOpts.shouldAllowStaleData = false;
clientOpts.shouldGenerateRandomSeq = false;
clientOpts.shouldPrintTimestamp = false;
clientOpts.nPings = 4;
clientOpts.interval = time::milliseconds(100);
clientOpts.timeout = time::milliseconds(2000);
clientOpts.startSeq = 1000;
client.reset(new client::Ping(*clientFace, clientOpts));
client->afterResponse.connect(bind(&PingIntegratedFixture::onData, this, _1));
client->afterTimeout.connect(bind(&PingIntegratedFixture::onTimeout, this, _1));
maxResponses = 4;
client->start();
this->advanceClocks(io, time::milliseconds(1), 400);
io.run();
BOOST_REQUIRE_EQUAL(4, server->getNPings());
}
BOOST_FIXTURE_TEST_CASE(Timeout, PingIntegratedFixture)
{
wantLoss = true;
server::Options serverOpts;
serverOpts.prefix = "ndn:/test-prefix";
serverOpts.freshnessPeriod = time::milliseconds(5000);
serverOpts.nMaxPings = 4;
serverOpts.shouldPrintTimestamp = false;
serverOpts.payloadSize = 0;
server.reset(new server::PingServer(*serverFace, m_keyChain, serverOpts));
BOOST_REQUIRE_EQUAL(0, server->getNPings());
server->start();
client::Options clientOpts;
clientOpts.prefix = "ndn:/test-prefix";
clientOpts.shouldAllowStaleData = false;
clientOpts.shouldGenerateRandomSeq = false;
clientOpts.shouldPrintTimestamp = false;
clientOpts.nPings = 4;
clientOpts.interval = time::milliseconds(100);
clientOpts.timeout = time::milliseconds(500);
clientOpts.startSeq = 1000;
client.reset(new client::Ping(*clientFace, clientOpts));
numResponses = 0;
maxResponses = 4;
client->afterResponse.connect(bind(&PingIntegratedFixture::onData, this, _1));
client->afterTimeout.connect(bind(&PingIntegratedFixture::onTimeout, this, _1));
client->start();
this->advanceClocks(io, time::milliseconds(1), 1000);
io.run();
BOOST_REQUIRE_EQUAL(0, server->getNPings());
}
BOOST_AUTO_TEST_SUITE_END()
} // namespace tests
} // namespace ping
} // namespace ndn
+97
View File
@@ -0,0 +1,97 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Arizona Board of Regents.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "tools/ping/server/ping-server.hpp"
#include <ndn-cxx/util/dummy-client-face.hpp>
#include "tests/test-common.hpp"
#include "../../identity-management-time-fixture.hpp"
namespace ndn {
namespace ping {
namespace server {
namespace tests {
using namespace ndn::tests;
BOOST_AUTO_TEST_SUITE(PingServerPingServer)
class CreatePingServerFixture : public IdentityManagementTimeFixture
{
protected:
CreatePingServerFixture()
: face(util::makeDummyClientFace(io, {false, true}))
, pingOptions(makeOptions())
, pingServer(*face, m_keyChain, pingOptions)
{
}
Interest
makePingInterest(int seq) const
{
Name name(pingOptions.prefix);
name.append("ping");
name.append(std::to_string(seq));
Interest interest(name);
interest.setMustBeFresh(true);
interest.setInterestLifetime(time::milliseconds(2000));
return interest;
}
private:
static Options
makeOptions()
{
Options opt;
opt.prefix = "ndn:/test-prefix";
opt.freshnessPeriod = time::milliseconds(5000);
opt.nMaxPings = 2;
opt.shouldPrintTimestamp = false;
opt.payloadSize = 0;
return opt;
}
protected:
boost::asio::io_service io;
shared_ptr<util::DummyClientFace> face;
Options pingOptions;
PingServer pingServer;
};
BOOST_FIXTURE_TEST_CASE(CreatePingServer, CreatePingServerFixture)
{
BOOST_REQUIRE_EQUAL(0, pingServer.getNPings());
pingServer.start();
this->advanceClocks(io, time::milliseconds(1), 200);
face->receive(makePingInterest(1000));
face->receive(makePingInterest(1001));
io.run();
BOOST_REQUIRE_EQUAL(2, pingServer.getNPings());
}
BOOST_AUTO_TEST_SUITE_END()
} // namespace tests
} // namespace server
} // namespace ping
} // namespace ndn
-2
View File
@@ -69,8 +69,6 @@ protected:
advanceClocks(boost::asio::io_service& io,
const time::nanoseconds& tick, size_t nTicks = 1)
{
BOOST_ASSERT(nTicks >= 0);
this->advanceClocks(io, tick, tick * nTicks);
}
+3 -4
View File
@@ -5,11 +5,10 @@ def build(bld):
if not bld.env['WITH_TESTS']:
return
tools = bld.path.ant_glob('*', dir=True, src=False)
bld(target='../unit-tests',
features='cxx cxxprogram',
source=bld.path.ant_glob('**/*.cpp'),
use=['core-objects'] + ['%s-objects' % tool for tool in tools],
source=bld.path.ant_glob(['*.cpp'] + ['%s/**/*.cpp' % tool for tool in bld.env['BUILD_TOOLS']]),
use=['core-objects'] + ['%s-objects' % tool for tool in bld.env['BUILD_TOOLS']],
headers='../common.hpp boost-test.hpp',
defines='TMP_TESTS_PATH=\"%s/tmp-tests\"' % bld.bldnode,
)
+73
View File
@@ -0,0 +1,73 @@
# ndncatchunks and ndnputchunks
**ndncatchunks** and **ndnputchunks** are a pair of programs to transfer a file as Data segments.
* **ndnputchunks** is a producer program that reads a file from the standard input, and makes
it available as NDN Data segments. It appends version and segment number components
to the specified name, according to the
[NDN naming conventions](http://named-data.net/publications/techreports/ndn-tr-22-ndn-memo-naming-conventions/).
* **ndncatchunks** is a consumer program that fetches Data segments of a file, optionally
discovering the latest version of the file, and writes the content of the retrieved file to
the standard output.
## Version discovery methods
* `fixed` : ndncatchunks will send an interest attempting to find a data packet with the
specified prefix and version number. A version component must be present at the
end of the user-specified NDN name.
* `iterative`: ndncatchunks will send a series of interests with ChildSelector set to prefer the
rightmost child and Exclude selectors, attempting to find a data packet with the
specified prefix and the latest (the largest in the NDN canonical ordering)
version number. The version is declared "latest" after a predefined number of
data retrieval timeouts (default: 1).
The default discovery method is `fixed`. Other methods will be implemented in future versions
of the tool.
## Usage examples
### Publishing
The following command will publish the text of the GPL-3 license under the `/localhost/demo/gpl3`
prefix:
ndnputchunks ndn:/localhost/demo/gpl3 < /usr/share/common-licenses/GPL-3
To find the published version you have to start ndnputchunks with the `-p` command line option,
for example:
ndnputchunks -p ndn:/localhost/demo/gpl3 < /usr/share/common-licenses/GPL-3
This command will print the published version to the standard output.
To publish data with a specific version, you must append a version component to the end of the
prefix. The version component must follow the aforementioned NDN naming conventions.
For example, the following command will publish the version `%FD%00%00%01Qc%CF%17v` of the
`/localhost/demo/gpl3` prefix:
ndnputchunks ndn:/localhost/demo/gpl3/%FD%00%00%01Qc%CF%17v < /usr/share/common-licenses/GPL-3
If the version component is not valid, a new well-formed version will be generated and appended
to the supplied NDN name.
### Retrieval
To retrieve the latest version of a published file, the following command can be used:
ndncatchunks -d iterative ndn:/localhost/demo/gpl3
This command will use the iterative method to discover the latest version of the file.
To fetch a specific version of a published file, you can use the `fixed` version discovery method
(the default). In this case the version needs to be supplied as part of the name. For example,
if the version is known to be `%FD%00%00%01Qc%CF%17v`, the following command will fetch that
exact version of the file:
ndncatchunks ndn:/localhost/demo/gpl3/%FD%00%00%01Qc%CF%17v
For more information, run the programs with `--help` as argument.
+110
View File
@@ -0,0 +1,110 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Wentao Shang
* @author Steve DiBenedetto
* @author Andrea Tosatto
*/
#include "consumer.hpp"
#include "discover-version.hpp"
namespace ndn {
namespace chunks {
Consumer::Consumer(Face& face, Validator& validator, bool isVerbose, std::ostream& os)
: m_face(face)
, m_validator(validator)
, m_pipeline(nullptr)
, m_nextToPrint(0)
, m_outputStream(os)
, m_isVerbose(isVerbose)
{
}
void Consumer::run(DiscoverVersion& discover, PipelineInterests& pipeline)
{
m_pipeline = &pipeline;
m_nextToPrint = 0;
discover.onDiscoverySuccess.connect(bind(&Consumer::runWithData, this, _1));
discover.onDiscoveryFailure.connect(bind(&Consumer::onFailure, this, _1));
discover.run();
m_face.processEvents();
}
void Consumer::runWithData(const Data& data)
{
m_validator.validate(data,
bind(&Consumer::onDataValidated, this, _1),
bind(&Consumer::onFailure, this, _2));
m_pipeline->runWithExcludedSegment(data,
bind(&Consumer::onData, this, _1, _2),
bind(&Consumer::onFailure, this, _1));
}
void
Consumer::onData(const Interest& interest, const Data& data)
{
m_validator.validate(data,
bind(&Consumer::onDataValidated, this, _1),
bind(&Consumer::onFailure, this, _2));
}
void
Consumer::onDataValidated(shared_ptr<const Data> data)
{
if (data->getContentType() == ndn::tlv::ContentType_Nack) {
if (m_isVerbose)
std::cerr << "Application level NACK: " << *data << std::endl;
m_pipeline->cancel();
throw ApplicationNackError(*data);
}
m_bufferedData[data->getName()[-1].toSegment()] = data;
writeInOrderData();
}
void
Consumer::onFailure(const std::string& reason)
{
throw std::runtime_error(reason);
}
void
Consumer::writeInOrderData()
{
for (auto it = m_bufferedData.begin();
it != m_bufferedData.end() && it->first == m_nextToPrint;
it = m_bufferedData.erase(it), ++m_nextToPrint) {
const Block& content = it->second->getContent();
m_outputStream.write(reinterpret_cast<const char*>(content.value()), content.value_size());
}
}
} // namespace chunks
} // namespace ndn
+103
View File
@@ -0,0 +1,103 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Wentao Shang
* @author Steve DiBenedetto
* @author Andrea Tosatto
*/
#ifndef NDN_TOOLS_CHUNKS_CATCHUNKS_CONSUMER_HPP
#define NDN_TOOLS_CHUNKS_CATCHUNKS_CONSUMER_HPP
#include "pipeline-interests.hpp"
#include "discover-version.hpp"
#include <ndn-cxx/security/validator.hpp>
namespace ndn {
namespace chunks {
/**
* @brief Segmented version consumer
*
* Discover the latest version of the data published under a specified prefix, and retrieve all the
* segments associated to that version. The segments are fetched in order and written to a
* user-specified stream in the same order.
*/
class Consumer : noncopyable
{
public:
class ApplicationNackError : public std::runtime_error
{
public:
explicit
ApplicationNackError(const Data& data)
: std::runtime_error("Application generated Nack: " + boost::lexical_cast<std::string>(data))
{
}
};
/**
* @brief Create the consumer
*/
Consumer(Face& face, Validator& validator, bool isVerbose, std::ostream& os = std::cout);
/**
* @brief Run the consumer
*/
void
run(DiscoverVersion& discover, PipelineInterests& pipeline);
private:
void
runWithData(const Data& data);
void
onData(const Interest& interest, const Data& data);
void
onDataValidated(shared_ptr<const Data> data);
void
onFailure(const std::string& reason);
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
void
writeInOrderData();
private:
Face& m_face;
Validator& m_validator;
PipelineInterests* m_pipeline;
uint64_t m_nextToPrint;
std::ostream& m_outputStream;
bool m_isVerbose;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
std::map<uint64_t, shared_ptr<const Data>> m_bufferedData;
};
} // namespace chunks
} // namespace ndn
#endif // NDN_TOOLS_CHUNKS_CATCHUNKS_CONSUMER_HPP
+181
View File
@@ -0,0 +1,181 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Andrea Tosatto
* @author Davide Pesavento
*/
#include "data-fetcher.hpp"
#include <cmath>
namespace ndn {
namespace chunks {
const int DataFetcher::MAX_RETRIES_INFINITE = -1;
const time::milliseconds DataFetcher::MAX_CONGESTION_BACKOFF_TIME = time::seconds(10);
shared_ptr<DataFetcher>
DataFetcher::fetch(Face& face, const Interest& interest, int maxNackRetries, int maxTimeoutRetries,
DataCallback onData, FailureCallback onNack, FailureCallback onTimeout,
bool isVerbose)
{
auto dataFetcher = shared_ptr<DataFetcher>(new DataFetcher(face,
maxNackRetries,
maxTimeoutRetries,
std::move(onData),
std::move(onNack),
std::move(onTimeout),
isVerbose));
dataFetcher->expressInterest(interest, dataFetcher);
return dataFetcher;
}
DataFetcher::DataFetcher(Face& face, int maxNackRetries, int maxTimeoutRetries,
DataCallback onData, FailureCallback onNack, FailureCallback onTimeout,
bool isVerbose)
: m_face(face)
, m_scheduler(m_face.getIoService())
, m_onData(std::move(onData))
, m_onNack(std::move(onNack))
, m_onTimeout(std::move(onTimeout))
, m_maxNackRetries(maxNackRetries)
, m_maxTimeoutRetries(maxTimeoutRetries)
, m_nNacks(0)
, m_nTimeouts(0)
, m_nCongestionRetries(0)
, m_isVerbose(isVerbose)
, m_isStopped(false)
, m_hasError(false)
{
BOOST_ASSERT(m_onData != nullptr);
}
void
DataFetcher::cancel()
{
if (isRunning()) {
m_isStopped = true;
m_face.removePendingInterest(m_interestId);
m_scheduler.cancelAllEvents();
}
}
void
DataFetcher::expressInterest(const Interest& interest, const shared_ptr<DataFetcher>& self)
{
m_nCongestionRetries = 0;
m_interestId = m_face.expressInterest(interest,
bind(&DataFetcher::handleData, this, _1, _2, self),
bind(&DataFetcher::handleNack, this, _1, _2, self),
bind(&DataFetcher::handleTimeout, this, _1, self));
}
void
DataFetcher::handleData(const Interest& interest, const Data& data,
const shared_ptr<DataFetcher>& self)
{
if (!isRunning())
return;
m_isStopped = true;
m_onData(interest, data);
}
void
DataFetcher::handleNack(const Interest& interest, const lp::Nack& nack,
const shared_ptr<DataFetcher>& self)
{
if (!isRunning())
return;
if (m_maxNackRetries != MAX_RETRIES_INFINITE)
++m_nNacks;
if (m_isVerbose)
std::cerr << "Received Nack with reason " << nack.getReason()
<< " for Interest " << interest << std::endl;
if (m_nNacks <= m_maxNackRetries || m_maxNackRetries == MAX_RETRIES_INFINITE) {
Interest newInterest(interest);
newInterest.refreshNonce();
switch (nack.getReason()) {
case lp::NackReason::DUPLICATE: {
expressInterest(newInterest, self);
break;
}
case lp::NackReason::CONGESTION: {
time::milliseconds backoffTime(static_cast<uint64_t>(std::pow(2, m_nCongestionRetries)));
if (backoffTime > MAX_CONGESTION_BACKOFF_TIME)
backoffTime = MAX_CONGESTION_BACKOFF_TIME;
else
m_nCongestionRetries++;
m_scheduler.scheduleEvent(backoffTime, bind(&DataFetcher::expressInterest, this,
newInterest, self));
break;
}
default: {
m_hasError = true;
if (m_onNack)
m_onNack(interest, "Could not retrieve data for " + interest.getName().toUri() +
", reason: " + boost::lexical_cast<std::string>(nack.getReason()));
break;
}
}
}
else {
m_hasError = true;
if (m_onNack)
m_onNack(interest, "Reached the maximum number of nack retries (" + to_string(m_maxNackRetries) +
") while retrieving data for " + interest.getName().toUri());
}
}
void
DataFetcher::handleTimeout(const Interest& interest, const shared_ptr<DataFetcher>& self)
{
if (!isRunning())
return;
if (m_maxTimeoutRetries != MAX_RETRIES_INFINITE)
++m_nTimeouts;
if (m_isVerbose)
std::cerr << "Timeout for Interest " << interest << std::endl;
if (m_nTimeouts <= m_maxTimeoutRetries || m_maxTimeoutRetries == MAX_RETRIES_INFINITE) {
Interest newInterest(interest);
newInterest.refreshNonce();
expressInterest(newInterest, self);
}
else {
m_hasError = true;
if (m_onTimeout)
m_onTimeout(interest, "Reached the maximum number of timeout retries (" + to_string(m_maxTimeoutRetries) +
") while retrieving data for " + interest.getName().toUri());
}
}
} // namespace chunks
} // namespace ndn
+132
View File
@@ -0,0 +1,132 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Andrea Tosatto
* @author Davide Pesavento
*/
#ifndef NDN_TOOLS_CHUNKS_CATCHUNKS_DATA_FETCHER_HPP
#define NDN_TOOLS_CHUNKS_CATCHUNKS_DATA_FETCHER_HPP
#include "core/common.hpp"
namespace ndn {
namespace chunks {
/**
* @brief fetch data for a given interest and handle timeout or nack error with retries
*
* To instantiate a DataFetcher you need to use the static method fetch, this will also express the
* interest. After a timeout or nack is received, the same interest with a different nonce will be
* requested for a maximum number of time specified by the class user. There are separate retry
* counters for timeouts and nacks.
*
* A specified callback is called after the data matching the expressed interest is received. A
* different callback is called in case one of the retries counter reach the maximum. This callback
* can be different for timeout and nack. The data callback must be defined but the others callback
* are optional.
*
*/
class DataFetcher
{
public:
/**
* @brief means that there is no maximum number of retries,
* i.e. fetching must be retried indefinitely
*/
static const int MAX_RETRIES_INFINITE;
/**
* @brief ceiling value for backoff time used in congestion handling
*/
static const time::milliseconds MAX_CONGESTION_BACKOFF_TIME;
typedef function<void(const Interest& interest, const std::string& reason)> FailureCallback;
/**
* @brief instantiate a DataFetcher object and start fetching data
*
* @param onData callback for segment correctly received, must not be empty
*/
static shared_ptr<DataFetcher>
fetch(Face& face, const Interest& interest, int maxNackRetries, int maxTimeoutRetries,
DataCallback onData, FailureCallback onTimeout, FailureCallback onNack,
bool isVerbose);
/**
* @brief stop data fetching without error and calling any callback
*/
void
cancel();
bool
isRunning() const
{
return !m_isStopped && !m_hasError;
}
bool
hasError() const
{
return m_hasError;
}
private:
DataFetcher(Face& face, int maxNackRetries, int maxTimeoutRetries,
DataCallback onData, FailureCallback onNack, FailureCallback onTimeout,
bool isVerbose);
void
expressInterest(const Interest& interest, const shared_ptr<DataFetcher>& self);
void
handleData(const Interest& interest, const Data& data, const shared_ptr<DataFetcher>& self);
void
handleNack(const Interest& interest, const lp::Nack& nack, const shared_ptr<DataFetcher>& self);
void
handleTimeout(const Interest& interest, const shared_ptr<DataFetcher>& self);
private:
Face& m_face;
Scheduler m_scheduler;
const PendingInterestId* m_interestId;
DataCallback m_onData;
FailureCallback m_onNack;
FailureCallback m_onTimeout;
int m_maxNackRetries;
int m_maxTimeoutRetries;
int m_nNacks;
int m_nTimeouts;
uint32_t m_nCongestionRetries;
bool m_isVerbose;
bool m_isStopped;
bool m_hasError;
};
} // namespace chunks
} // namespace ndn
#endif // NDN_TOOLS_CHUNKS_CATCHUNKS_DATA_FETCHER_HPP
@@ -0,0 +1,78 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Andrea Tosatto
*/
#include "discover-version-fixed.hpp"
#include <cmath>
#include <boost/lexical_cast.hpp>
namespace ndn {
namespace chunks {
DiscoverVersionFixed::DiscoverVersionFixed(const Name& prefix, Face& face, const Options& options)
: Options(options)
, DiscoverVersion(prefix, face, options)
, m_strayExcludes()
{
}
void
DiscoverVersionFixed::run()
{
Interest interest(m_prefix);
interest.setInterestLifetime(interestLifetime);
interest.setMustBeFresh(mustBeFresh);
interest.setMaxSuffixComponents(2);
interest.setMinSuffixComponents(2);
expressInterest(interest, maxRetriesOnTimeoutOrNack, maxRetriesOnTimeoutOrNack);
}
void
DiscoverVersionFixed::handleData(const Interest& interest, const Data& data)
{
if (isVerbose)
std::cerr << "Data: " << data << std::endl;
size_t segmentIndex = interest.getName().size();
if (data.getName()[segmentIndex].isSegment()) {
if (isVerbose)
std::cerr << "Found data with the requested version: " << m_prefix[-1] << std::endl;
this->emitSignal(onDiscoverySuccess, data);
}
else {
// data isn't a valid segment, add to the exclude list
m_strayExcludes.excludeOne(data.getName()[segmentIndex]);
Interest newInterest(interest);
newInterest.refreshNonce();
newInterest.setExclude(m_strayExcludes);
expressInterest(newInterest, maxRetriesOnTimeoutOrNack, maxRetriesOnTimeoutOrNack);
}
}
} // namespace chunks
} // namespace ndn
@@ -0,0 +1,73 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Andrea Tosatto
*/
#ifndef NDN_TOOLS_CHUNKS_CATCHUNKS_DISCOVER_VERSION_FIXED_HPP
#define NDN_TOOLS_CHUNKS_CATCHUNKS_DISCOVER_VERSION_FIXED_HPP
#include "discover-version.hpp"
namespace ndn {
namespace chunks {
/**
* @brief Service to retrieve a specific version segment. The version is specified in the prefix
*
* Send a request of a specific version and expect to be answered with one segment.
*
* The received name component after version can be an invalid segment number, this component will
* be excluded in the next interests. In the unlikely case that there are too many excluded
* components such that the Interest cannot fit in ndn::MAX_NDN_PACKET_SIZE, the discovery
* procedure will throw Face::Error.
*
* DiscoverVersionFixed's user is notified once after one segment with the user specified version
* is found or on failure to find any Data version.
*/
class DiscoverVersionFixed : public DiscoverVersion
{
public:
/**
* @brief create a DiscoverVersionSpecified service
*/
DiscoverVersionFixed(const Name& prefix, Face& face, const Options& options);
/**
* @brief identify the latest Data version published.
*/
void
run() NDN_CXX_DECL_FINAL;
private:
void
handleData(const Interest& interest, const Data& data) NDN_CXX_DECL_FINAL;
private:
Exclude m_strayExcludes;
};
} // namespace chunks
} // namespace ndn
#endif // NDN_TOOLS_CHUNKS_CATCHUNKS_DISCOVER_VERSION_FIXED_HPP
@@ -0,0 +1,118 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Wentao Shang
* @author Steve DiBenedetto
* @author Andrea Tosatto
*/
#include "discover-version-iterative.hpp"
namespace ndn {
namespace chunks {
DiscoverVersionIterative::DiscoverVersionIterative(const Name& prefix, Face& face,
const Options& options)
: chunks::Options(options)
, DiscoverVersion(prefix, face, options)
, Options(options)
, m_latestVersion(0)
, m_latestVersionData(nullptr)
, m_foundVersion(false)
{
}
void
DiscoverVersionIterative::run()
{
m_latestVersion = 0;
m_foundVersion = false;
Interest interest(m_prefix);
interest.setInterestLifetime(interestLifetime);
interest.setMustBeFresh(mustBeFresh);
interest.setMinSuffixComponents(3);
interest.setMaxSuffixComponents(3);
interest.setChildSelector(1);
expressInterest(interest, maxRetriesOnTimeoutOrNack, maxRetriesOnTimeoutOrNack);
}
void
DiscoverVersionIterative::handleData(const Interest& interest, const Data& data)
{
size_t versionindex = m_prefix.size();
const Name& name = data.getName();
Exclude exclude;
if (isVerbose)
std::cerr << "Data: " << data << std::endl;
BOOST_ASSERT(name.size() > m_prefix.size());
if (name[versionindex].isVersion()) {
m_latestVersion = name[versionindex].toVersion();
m_latestVersionData = make_shared<Data>(data);
m_foundVersion = true;
exclude.excludeBefore(name[versionindex]);
if (isVerbose)
std::cerr << "Discovered version = " << m_latestVersion << std::endl;
}
else {
// didn't find a version number at expected index.
m_strayExcludes.excludeOne(name[versionindex]);
}
for (const auto& i : m_strayExcludes) {
exclude.excludeOne(i.first);
}
Interest newInterest(interest);
newInterest.refreshNonce();
newInterest.setExclude(exclude);
if (m_foundVersion)
expressInterest(newInterest, maxRetriesOnTimeoutOrNack, maxRetriesAfterVersionFound);
else
expressInterest(interest, maxRetriesOnTimeoutOrNack, maxRetriesOnTimeoutOrNack);
}
void
DiscoverVersionIterative::handleTimeout(const Interest& interest, const std::string& reason)
{
if (m_foundVersion) {
// a version has been found and after a timeout error this version can be used as the latest.
if (isVerbose)
std::cerr << "Found data with the latest version: " << m_latestVersion << std::endl;
// we discovered at least one version. assume what we have is the latest.
this->emitSignal(onDiscoverySuccess, *m_latestVersionData);
}
else {
DiscoverVersion::handleTimeout(interest, reason);
}
}
} // namespace chunks
} // namespace ndn
@@ -0,0 +1,107 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Wentao Shang
* @author Steve DiBenedetto
* @author Andrea Tosatto
*/
#ifndef NDN_TOOLS_CHUNKS_CATCHUNKS_DISCOVER_VERSION_ITERATIVE_HPP
#define NDN_TOOLS_CHUNKS_CATCHUNKS_DISCOVER_VERSION_ITERATIVE_HPP
#include "discover-version.hpp"
namespace ndn {
namespace chunks {
/**
* @brief Options for discover version iterative DiscoverVersionIterative
*
* The canonical name to use is DiscoverVersionIterative::Options
*/
class DiscoverVersionIterativeOptions : public virtual Options
{
public:
explicit
DiscoverVersionIterativeOptions(const Options& opt = Options())
: Options(opt)
, maxRetriesAfterVersionFound(1)
{
}
public:
int maxRetriesAfterVersionFound; // used only in timeout handling
};
/**
* @brief Service for discovering the latest Data version in the iterative way
*
* Identifies the latest retrievable version published under the specified namespace
* (as specified by the Version marker).
*
* DiscoverVersionIterative declares the largest discovered version to be the latest after some
* Interest timeouts (i.e. failed retrieval after exclusion and retransmission). The number of
* timeouts are specified by the value of maxRetriesAfterVersionFound inside the iterative options.
*
* The received name component after version can be an invalid segment number, this component will
* be excluded in the next interests. In the unlikely case that there are too many excluded
* components such that the Interest cannot fit in ndn::MAX_NDN_PACKET_SIZE, the discovery
* procedure will throw Face::Error.
*
* DiscoverVersionIterative's user is notified once after identifying the latest retrievable
* version or on failure to find any version Data.
*/
class DiscoverVersionIterative : public DiscoverVersion, protected DiscoverVersionIterativeOptions
{
public:
typedef DiscoverVersionIterativeOptions Options;
public:
/**
* @brief create a DiscoverVersionIterative service
*/
DiscoverVersionIterative(const Name& prefix, Face& face, const Options& options);
/**
* @brief identify the latest Data version published.
*/
void
run() NDN_CXX_DECL_FINAL;
private:
void
handleData(const Interest& interest, const Data& data) NDN_CXX_DECL_FINAL;
void
handleTimeout(const Interest& interest, const std::string& reason) NDN_CXX_DECL_FINAL;
private:
uint64_t m_latestVersion;
shared_ptr<const Data> m_latestVersionData;
Exclude m_strayExcludes;
bool m_foundVersion;
};
} // namespace chunks
} // namespace ndn
#endif // NDN_TOOLS_CHUNKS_CATCHUNKS_DISCOVER_VERSION_ITERATIVE_HPP
@@ -0,0 +1,71 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Wentao Shang
* @author Steve DiBenedetto
* @author Andrea Tosatto
*/
#include "discover-version.hpp"
#include "data-fetcher.hpp"
namespace ndn {
namespace chunks {
DiscoverVersion::DiscoverVersion(const Name& prefix, Face& face, const Options& options)
: Options(options)
, m_prefix(prefix)
, m_face(face)
{
}
void
DiscoverVersion::expressInterest(const Interest& interest, int maxRetriesNack,
int maxRetriesTimeout)
{
fetcher = DataFetcher::fetch(m_face, interest, maxRetriesNack, maxRetriesTimeout,
bind(&DiscoverVersion::handleData, this, _1, _2),
bind(&DiscoverVersion::handleNack, this, _1, _2),
bind(&DiscoverVersion::handleTimeout, this, _1, _2),
isVerbose);
}
void
DiscoverVersion::handleData(const Interest& interest, const Data& data)
{
onDiscoverySuccess(data);
}
void
DiscoverVersion::handleNack(const Interest& interest, const std::string& reason)
{
onDiscoveryFailure(reason);
}
void
DiscoverVersion::handleTimeout(const Interest& interest, const std::string& reason)
{
onDiscoveryFailure(reason);
}
} // namespace chunks
} // namespace ndn
@@ -0,0 +1,95 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Wentao Shang
* @author Steve DiBenedetto
* @author Andrea Tosatto
*/
#ifndef NDN_TOOLS_CHUNKS_CATCHUNKS_DISCOVER_VERSION_HPP
#define NDN_TOOLS_CHUNKS_CATCHUNKS_DISCOVER_VERSION_HPP
#include "core/common.hpp"
#include "options.hpp"
namespace ndn {
namespace chunks {
class DataFetcher;
/**
* @brief Base class of services for discovering the latest Data version
*
* DiscoverVersion's user is notified once after identifying the latest retrievable version or
* on failure to find any Data version.
*/
class DiscoverVersion : virtual protected Options, noncopyable
{
public: // signals
/**
* @brief Signal emited when the first segment of a specific version is found.
*/
signal::Signal<DiscoverVersion, const Data&> onDiscoverySuccess;
/**
* @brief Signal emitted when a failure occurs.
*/
signal::Signal<DiscoverVersion, const std::string&> onDiscoveryFailure;
DECLARE_SIGNAL_EMIT(onDiscoverySuccess)
DECLARE_SIGNAL_EMIT(onDiscoveryFailure)
public:
/**
* @brief create a DiscoverVersion service
*/
DiscoverVersion(const Name& prefix, Face& face, const Options& options);
/**
* @brief identify the latest Data version published.
*/
virtual void
run() = 0;
protected:
void
expressInterest(const Interest& interest, int maxRetriesNack, int maxRetriesTimeout);
virtual void
handleData(const Interest& interest, const Data& data);
virtual void
handleNack(const Interest& interest, const std::string& reason);
virtual void
handleTimeout(const Interest& interest, const std::string& reason);
protected:
const Name m_prefix;
Face& m_face;
shared_ptr<DataFetcher> fetcher;
};
} // namespace chunks
} // namespace ndn
#endif // NDN_TOOLS_CHUNKS_CATCHUNKS_DISCOVER_VERSION_HPP
+180
View File
@@ -0,0 +1,180 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Wentao Shang
* @author Steve DiBenedetto
* @author Andrea Tosatto
*/
#include "core/version.hpp"
#include "options.hpp"
#include "consumer.hpp"
#include "discover-version-fixed.hpp"
#include "discover-version-iterative.hpp"
#include <ndn-cxx/security/validator-null.hpp>
namespace ndn {
namespace chunks {
static int
main(int argc, char** argv)
{
std::string programName(argv[0]);
Options options;
std::string discoverType("fixed");
size_t maxPipelineSize(1);
int maxRetriesAfterVersionFound(1);
std::string uri;
namespace po = boost::program_options;
po::options_description visibleDesc("Options");
visibleDesc.add_options()
("help,h", "print this help message and exit")
("discover-version,d", po::value<std::string>(&discoverType)->default_value(discoverType),
"version discovery algorithm to use; valid values are: 'fixed', 'iterative'")
("fresh,f", po::bool_switch(&options.mustBeFresh), "only return fresh content")
("lifetime,l", po::value<uint64_t>()->default_value(options.interestLifetime.count()),
"lifetime of expressed Interests, in milliseconds")
("pipeline,p", po::value<size_t>(&maxPipelineSize)->default_value(maxPipelineSize),
"maximum size of the Interest pipeline")
("retries,r", po::value<int>(&options.maxRetriesOnTimeoutOrNack)->default_value(options.maxRetriesOnTimeoutOrNack),
"maximum number of retries in case of Nack or timeout (-1 = no limit)")
("retries-iterative,i", po::value<int>(&maxRetriesAfterVersionFound)->default_value(maxRetriesAfterVersionFound),
"number of timeouts that have to occur in order to confirm a discovered Data "
"version as the latest one (only applicable to 'iterative' version discovery)")
("verbose,v", po::bool_switch(&options.isVerbose), "turn on verbose output")
("version,V", "print program version and exit")
;
po::options_description hiddenDesc("Hidden options");
hiddenDesc.add_options()
("ndn-name,n", po::value<std::string>(&uri), "NDN name of the requested content");
po::positional_options_description p;
p.add("ndn-name", -1);
po::options_description optDesc("Allowed options");
optDesc.add(visibleDesc).add(hiddenDesc);
po::variables_map vm;
try {
po::store(po::command_line_parser(argc, argv).options(optDesc).positional(p).run(), vm);
po::notify(vm);
}
catch (const po::error& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
return 2;
}
catch (const boost::bad_any_cast& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
return 2;
}
if (vm.count("help") > 0) {
std::cout << "Usage: " << programName << " [options] ndn:/name" << std::endl;
std::cout << visibleDesc;
return 0;
}
if (vm.count("version") > 0) {
std::cout << "ndncatchunks " << tools::VERSION << std::endl;
return 0;
}
if (vm.count("ndn-name") == 0) {
std::cerr << "Usage: " << programName << " [options] ndn:/name" << std::endl;
std::cerr << visibleDesc;
return 2;
}
Name prefix(uri);
if (discoverType == "fixed" && (prefix.empty() || !prefix[-1].isVersion())) {
std::cerr << "ERROR: The specified name must contain a version component when using "
"fixed version discovery" << std::endl;
return 2;
}
if (maxPipelineSize < 1 || maxPipelineSize > 1024) {
std::cerr << "ERROR: pipeline size must be between 1 and 1024" << std::endl;
return 2;
}
if (options.maxRetriesOnTimeoutOrNack < -1 || options.maxRetriesOnTimeoutOrNack > 1024) {
std::cerr << "ERROR: retries value must be between -1 and 1024" << std::endl;
return 2;
}
if (maxRetriesAfterVersionFound < 0 || maxRetriesAfterVersionFound > 1024) {
std::cerr << "ERROR: retries iterative value must be between 0 and 1024" << std::endl;
return 2;
}
options.interestLifetime = time::milliseconds(vm["lifetime"].as<uint64_t>());
try {
Face face;
unique_ptr<DiscoverVersion> discover;
if (discoverType == "fixed") {
discover = make_unique<DiscoverVersionFixed>(prefix, face, options);
}
else if (discoverType == "iterative") {
DiscoverVersionIterative::Options optionsIterative(options);
optionsIterative.maxRetriesAfterVersionFound = maxRetriesAfterVersionFound;
discover = make_unique<DiscoverVersionIterative>(prefix, face, optionsIterative);
}
else {
std::cerr << "ERROR: discover version type not valid" << std::endl;
return 2;
}
ValidatorNull validator;
Consumer consumer(face, validator, options.isVerbose);
PipelineInterests::Options optionsPipeline(options);
optionsPipeline.maxPipelineSize = maxPipelineSize;
PipelineInterests pipeline(face, optionsPipeline);
BOOST_ASSERT(discover != nullptr);
consumer.run(*discover, pipeline);
}
catch (const Consumer::ApplicationNackError& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
return 3;
}
catch (const std::exception& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
return 1;
}
return 0;
}
} // namespace chunks
} // namespace ndn
int
main(int argc, char** argv)
{
return ndn::chunks::main(argc, argv);
}
+43
View File
@@ -0,0 +1,43 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Andrea Tosatto
* @author Davide Pesavento
*/
#include "options.hpp"
#include <ndn-cxx/interest.hpp>
namespace ndn {
namespace chunks {
Options::Options()
: interestLifetime(ndn::DEFAULT_INTEREST_LIFETIME)
, maxRetriesOnTimeoutOrNack(3)
, mustBeFresh(false)
, isVerbose(false)
{
}
} // namespace chunks
} // namespace ndn
+50
View File
@@ -0,0 +1,50 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Andrea Tosatto
* @author Davide Pesavento
*/
#ifndef NDN_TOOLS_CHUNKS_CATCHUNKS_OPTIONS_HPP
#define NDN_TOOLS_CHUNKS_CATCHUNKS_OPTIONS_HPP
#include <ndn-cxx/util/time.hpp>
namespace ndn {
namespace chunks {
class Options
{
public:
Options();
public:
time::milliseconds interestLifetime;
int maxRetriesOnTimeoutOrNack;
bool mustBeFresh;
bool isVerbose;
};
} // namespace chunks
} // namespace ndn
#endif // NDN_TOOLS_CHUNKS_CATCHUNKS_OPTIONS_HPP
@@ -0,0 +1,202 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Wentao Shang
* @author Steve DiBenedetto
* @author Andrea Tosatto
*/
#include "pipeline-interests.hpp"
#include "data-fetcher.hpp"
namespace ndn {
namespace chunks {
PipelineInterests::PipelineInterests(Face& face, const Options& options)
: m_face(face)
, m_nextSegmentNo(0)
, m_lastSegmentNo(0)
, m_excludeSegmentNo(0)
, m_options(options)
, m_hasFinalBlockId(false)
, m_hasError(false)
, m_hasFailure(false)
{
m_segmentFetchers.resize(m_options.maxPipelineSize);
}
PipelineInterests::~PipelineInterests()
{
cancel();
}
void
PipelineInterests::runWithExcludedSegment(const Data& data, DataCallback onData,
FailureCallback onFailure)
{
BOOST_ASSERT(onData != nullptr);
m_onData = std::move(onData);
m_onFailure = std::move(onFailure);
Name dataName = data.getName();
m_prefix = dataName.getPrefix(-1);
m_excludeSegmentNo = dataName[-1].toSegment();
if (!data.getFinalBlockId().empty()) {
m_hasFinalBlockId = true;
m_lastSegmentNo = data.getFinalBlockId().toSegment();
}
// if the FinalBlockId is unknown, this could potentially request non-existent segments
for (size_t nRequestedSegments = 0; nRequestedSegments < m_options.maxPipelineSize;
nRequestedSegments++) {
if (!fetchNextSegment(nRequestedSegments)) // all segments have been requested
break;
}
}
bool
PipelineInterests::fetchNextSegment(std::size_t pipeNo)
{
if (m_hasFailure) {
fail("Fetching terminated but no final segment number has been found");
return false;
}
if (m_nextSegmentNo == m_excludeSegmentNo)
m_nextSegmentNo++;
if (m_hasFinalBlockId && m_nextSegmentNo > m_lastSegmentNo)
return false;
// Send interest for next segment
if (m_options.isVerbose)
std::cerr << "Requesting segment #" << m_nextSegmentNo << std::endl;
Interest interest(Name(m_prefix).appendSegment(m_nextSegmentNo));
interest.setInterestLifetime(m_options.interestLifetime);
interest.setMustBeFresh(m_options.mustBeFresh);
interest.setMaxSuffixComponents(1);
BOOST_ASSERT(!m_segmentFetchers[pipeNo].first || !m_segmentFetchers[pipeNo].first->isRunning());
auto fetcher = DataFetcher::fetch(m_face, interest,
m_options.maxRetriesOnTimeoutOrNack,
m_options.maxRetriesOnTimeoutOrNack,
bind(&PipelineInterests::handleData, this, _1, _2, pipeNo),
bind(&PipelineInterests::handleFail, this, _2, pipeNo),
bind(&PipelineInterests::handleFail, this, _2, pipeNo),
m_options.isVerbose);
m_segmentFetchers[pipeNo] = make_pair(fetcher, m_nextSegmentNo);
m_nextSegmentNo++;
return true;
}
void
PipelineInterests::cancel()
{
for (auto& fetcher : m_segmentFetchers)
if (fetcher.first)
fetcher.first->cancel();
m_segmentFetchers.clear();
}
void
PipelineInterests::fail(const std::string& reason)
{
if (!m_hasError) {
cancel();
m_hasError = true;
m_hasFailure = true;
if (m_onFailure)
m_face.getIoService().post([this, reason] { m_onFailure(reason); });
}
}
void
PipelineInterests::handleData(const Interest& interest, const Data& data, size_t pipeNo)
{
if (m_hasError)
return;
BOOST_ASSERT(data.getName().equals(interest.getName()));
if (m_options.isVerbose)
std::cerr << "Received segment #" << data.getName()[-1].toSegment() << std::endl;
m_onData(interest, data);
if (!m_hasFinalBlockId && !data.getFinalBlockId().empty()) {
m_lastSegmentNo = data.getFinalBlockId().toSegment();
m_hasFinalBlockId = true;
for (auto& fetcher : m_segmentFetchers) {
if (fetcher.first && fetcher.second > m_lastSegmentNo) {
// Stop trying to fetch segments that are not part of the content
fetcher.first->cancel();
}
else if (fetcher.first && fetcher.first->hasError()) { // fetcher.second <= m_lastSegmentNo
// there was an error while fetching a segment that is part of the content
fail("Failure retriving segment #" + to_string(fetcher.second));
return;
}
}
}
fetchNextSegment(pipeNo);
}
void PipelineInterests::handleFail(const std::string& reason, std::size_t pipeNo)
{
if (m_hasError)
return;
if (m_hasFinalBlockId && m_segmentFetchers[pipeNo].second <= m_lastSegmentNo) {
fail(reason);
}
else if (!m_hasFinalBlockId) {
// don't fetch the following segments
bool areAllFetchersStopped = true;
for (auto& fetcher : m_segmentFetchers) {
if (fetcher.first && fetcher.second > m_segmentFetchers[pipeNo].second) {
fetcher.first->cancel();
}
else if (fetcher.first && fetcher.first->isRunning()) {
// fetcher.second <= m_segmentFetchers[pipeNo].second
areAllFetchersStopped = false;
}
}
if (areAllFetchersStopped) {
if (m_onFailure)
fail("Fetching terminated but no final segment number has been found");
}
else {
m_hasFailure = true;
}
}
}
} // namespace chunks
} // namespace ndn
@@ -0,0 +1,143 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Wentao Shang
* @author Steve DiBenedetto
* @author Andrea Tosatto
*/
#ifndef NDN_TOOLS_CHUNKS_CATCHUNKS_PIPELINE_INTERESTS_HPP
#define NDN_TOOLS_CHUNKS_CATCHUNKS_PIPELINE_INTERESTS_HPP
#include "core/common.hpp"
#include "options.hpp"
namespace ndn {
namespace chunks {
class DataFetcher;
class PipelineInterestsOptions : public Options
{
public:
explicit
PipelineInterestsOptions(const Options& options = Options())
: Options(options)
, maxPipelineSize(1)
{
}
public:
size_t maxPipelineSize;
};
/**
* @brief Service for retrieving Data via an Interest pipeline
*
* Retrieves all segmented Data under the specified prefix by maintaining a pipeline of N Interests
* in flight.
*
* Provides retrieved Data on arrival with no ordering guarantees. Data is delivered to the
* PipelineInterests' user via callback immediately upon arrival.
*/
class PipelineInterests
{
public:
typedef PipelineInterestsOptions Options;
typedef function<void(const std::string& reason)> FailureCallback;
public:
/**
* @brief create a PipelineInterests service
*
* Configures the pipelining service without specifying the retrieval namespace. After this
* configuration the method runWithExcludedSegment must be called to run the Pipeline.
*/
explicit
PipelineInterests(Face& face, const Options& options = Options());
~PipelineInterests();
/**
* @brief fetch all the segments between 0 and lastSegment of the specified prefix
*
* Starts the pipeline of size defined inside the options. The pipeline retrieves all the segments
* until the last segment is received, @p data is excluded from the retrieving.
*
* @param data a segment of the segmented Data to retrive; data.getName() must end with a segment
* number
* @param onData callback for every segment correctly received, must not be empty
* @param onfailure callback called if an error occurs
*/
void
runWithExcludedSegment(const Data& data, DataCallback onData, FailureCallback onFailure);
/**
* @brief stop all fetch operations
*/
void
cancel();
private:
/**
* @brief fetch the next segment that has not been requested yet
*
* @return false if there is an error or all the segments have been fetched, true otherwise
*/
bool
fetchNextSegment(size_t pipeNo);
void
fail(const std::string& reason);
void
handleData(const Interest& interest, const Data& data, size_t pipeNo);
void
handleFail(const std::string& reason, size_t pipeNo);
private:
Name m_prefix;
Face& m_face;
uint64_t m_nextSegmentNo;
uint64_t m_lastSegmentNo;
uint64_t m_excludeSegmentNo;
DataCallback m_onData;
FailureCallback m_onFailure;
const Options m_options;
std::vector<std::pair<shared_ptr<DataFetcher>, uint64_t>> m_segmentFetchers;
bool m_hasFinalBlockId;
/**
* true if there's a critical error
*/
bool m_hasError;
/**
* true if one or more segmentFetcher failed, if lastSegmentNo is not set this is usually not a
* fatal error for the pipeline
*/
bool m_hasFailure;
};
} // namespace chunks
} // namespace ndn
#endif // NDN_TOOLS_CHUNKS_CATCHUNKS_PIPELINE_INTERESTS_HPP
+137
View File
@@ -0,0 +1,137 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Wentao Shang
* @author Steve DiBenedetto
* @author Andrea Tosatto
*/
#include "core/version.hpp"
#include "producer.hpp"
namespace ndn {
namespace chunks {
static int
main(int argc, char** argv)
{
std::string programName = argv[0];
uint64_t freshnessPeriod = 10000;
bool printVersion = false;
size_t maxChunkSize = MAX_NDN_PACKET_SIZE >> 1;
std::string signingStr;
bool isVerbose = false;
std::string prefix;
namespace po = boost::program_options;
po::options_description visibleDesc("Options");
visibleDesc.add_options()
("help,h", "print this help message and exit")
("freshness,f", po::value<uint64_t>(&freshnessPeriod)->default_value(freshnessPeriod),
"specify FreshnessPeriod, in milliseconds")
("print-data-version,p", po::bool_switch(&printVersion), "print Data version to the standard output")
("size,s", po::value<size_t>(&maxChunkSize)->default_value(maxChunkSize),
"maximum chunk size, in bytes")
("signing-info,S", po::value<std::string>(&signingStr)->default_value(signingStr),
"set signing information")
("verbose,v", po::bool_switch(&isVerbose), "turn on verbose output")
("version,V", "print program version and exit")
;
po::options_description hiddenDesc("Hidden options");
hiddenDesc.add_options()
("ndn-name,n", po::value<std::string>(&prefix), "NDN name for the served content");
po::positional_options_description p;
p.add("ndn-name", -1);
po::options_description optDesc("Allowed options");
optDesc.add(visibleDesc).add(hiddenDesc);
po::variables_map vm;
try {
po::store(po::command_line_parser(argc, argv).options(optDesc).positional(p).run(), vm);
po::notify(vm);
}
catch (const po::error& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
return 2;
}
catch (const boost::bad_any_cast& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
return 2;
}
if (vm.count("help") > 0) {
std::cout << "Usage: " << programName << " [options] ndn:/name" << std::endl;
std::cout << visibleDesc;
return 0;
}
if (vm.count("version") > 0) {
std::cout << "ndnputchunks " << tools::VERSION << std::endl;
return 0;
}
if (prefix.empty()) {
std::cerr << "Usage: " << programName << " [options] ndn:/name" << std::endl;
std::cerr << visibleDesc;
return 2;
}
if (maxChunkSize < 1 || maxChunkSize > MAX_NDN_PACKET_SIZE) {
std::cerr << "ERROR: Maximum chunk size must be between 1 and " << MAX_NDN_PACKET_SIZE << std::endl;
return 2;
}
security::SigningInfo signingInfo;
try {
signingInfo = security::SigningInfo(signingStr);
}
catch (const std::invalid_argument& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
return 2;
}
try {
Face face;
KeyChain keyChain;
Producer producer(prefix, face, keyChain, signingInfo, time::milliseconds(freshnessPeriod),
maxChunkSize, isVerbose, printVersion, std::cin);
producer.run();
}
catch (const std::exception& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
return 1;
}
return 0;
}
} // namespace chunks
} // namespace ndn
int
main(int argc, char** argv)
{
return ndn::chunks::main(argc, argv);
}
+157
View File
@@ -0,0 +1,157 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Wentao Shang
* @author Steve DiBenedetto
* @author Andrea Tosatto
*/
#include "producer.hpp"
namespace ndn {
namespace chunks {
Producer::Producer(const Name& prefix,
Face& face,
KeyChain& keyChain,
const security::SigningInfo& signingInfo,
time::milliseconds freshnessPeriod,
size_t maxSegmentSize,
bool isVerbose,
bool needToPrintVersion,
std::istream& is)
: m_face(face)
, m_keyChain(keyChain)
, m_signingInfo(signingInfo)
, m_freshnessPeriod(freshnessPeriod)
, m_maxSegmentSize(maxSegmentSize)
, m_isVerbose(isVerbose)
{
if (prefix.size() > 0 && prefix[-1].isVersion()) {
m_prefix = prefix.getPrefix(-1);
m_versionedPrefix = prefix;
}
else {
m_prefix = prefix;
m_versionedPrefix = Name(m_prefix).appendVersion();
}
populateStore(is);
if (needToPrintVersion)
std::cout << m_versionedPrefix[-1] << std::endl;
m_face.setInterestFilter(m_prefix,
bind(&Producer::onInterest, this, _2),
RegisterPrefixSuccessCallback(),
bind(&Producer::onRegisterFailed, this, _1, _2));
if (m_isVerbose)
std::cerr << "Data published with name: " << m_versionedPrefix << std::endl;
}
void
Producer::run()
{
m_face.processEvents();
}
void
Producer::onInterest(const Interest& interest)
{
BOOST_ASSERT(m_store.size() > 0);
if (m_isVerbose)
std::cerr << "Interest: " << interest << std::endl;
const Name& name = interest.getName();
shared_ptr<Data> data;
// is this a discovery Interest or a sequence retrieval?
if (name.size() == m_versionedPrefix.size() + 1 && m_versionedPrefix.isPrefixOf(name) &&
name[-1].isSegment()) {
const auto segmentNo = static_cast<size_t>(interest.getName()[-1].toSegment());
// specific segment retrieval
if (segmentNo < m_store.size()) {
data = m_store[segmentNo];
}
}
else if (interest.matchesData(*m_store[0])) {
// Interest has version and is looking for the first segment or has no version
data = m_store[0];
}
if (data != nullptr) {
if (m_isVerbose)
std::cerr << "Data: " << *data << std::endl;
m_face.put(*data);
}
}
void
Producer::populateStore(std::istream& is)
{
BOOST_ASSERT(m_store.size() == 0);
if (m_isVerbose)
std::cerr << "Loading input ..." << std::endl;
std::vector<uint8_t> buffer(m_maxSegmentSize);
while (is.good()) {
is.read(reinterpret_cast<char*>(buffer.data()), buffer.size());
const auto nCharsRead = is.gcount();
if (nCharsRead > 0) {
auto data = make_shared<Data>(Name(m_versionedPrefix).appendSegment(m_store.size()));
data->setFreshnessPeriod(m_freshnessPeriod);
data->setContent(&buffer[0], nCharsRead);
m_store.push_back(data);
}
}
if (m_store.empty()) {
auto data = make_shared<Data>(Name(m_versionedPrefix).appendSegment(0));
data->setFreshnessPeriod(m_freshnessPeriod);
m_store.push_back(data);
}
auto finalBlockId = name::Component::fromSegment(m_store.size() - 1);
for (const auto& data : m_store) {
data->setFinalBlockId(finalBlockId);
m_keyChain.sign(*data, m_signingInfo);
}
if (m_isVerbose)
std::cerr << "Created " << m_store.size() << " chunks for prefix " << m_prefix << std::endl;
}
void
Producer::onRegisterFailed(const Name& prefix, const std::string& reason)
{
std::cerr << "ERROR: Failed to register prefix '"
<< prefix << "' (" << reason << ")" << std::endl;
m_face.shutdown();
}
} // namespace chunks
} // namespace ndn
+100
View File
@@ -0,0 +1,100 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2016, Regents of the University of California,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*
* @author Wentao Shang
* @author Steve DiBenedetto
* @author Andrea Tosatto
*/
#ifndef NDN_TOOLS_CHUNKS_PUTCHUNKS_PRODUCER_HPP
#define NDN_TOOLS_CHUNKS_PUTCHUNKS_PRODUCER_HPP
#include "core/common.hpp"
namespace ndn {
namespace chunks {
/**
* @brief Segmented version Producer
*
* Packetizes and publishes data from an input stream under /prefix/<version>/<segment number>.
* The current time is used as the version number. The store has always at least one element (also
* with empty input stream).
*/
class Producer : noncopyable
{
public:
/**
* @brief Create the Producer
*
* @prefix prefix used to publish data, if the last component of prefix is not a version number
* the current time is used as version number.
*/
Producer(const Name& prefix, Face& face, KeyChain& keyChain,
const security::SigningInfo& signingInfo, time::milliseconds freshnessPeriod,
size_t maxSegmentSize, bool isVerbose = false, bool needToPrintVersion = false,
std::istream& is = std::cin);
/**
* @brief Run the Producer
*/
void
run();
private:
void
onInterest(const Interest& interest);
/**
* @brief Split the input stream in data packets and save them to the store
*
* Create data packets reading all the characters from the input stream until EOF, or an
* error occurs. Each data packet has a maximum payload size of m_maxSegmentSize value and is
* stored inside the vector m_store. An empty data packet is created and stored if the input
* stream is empty.
*
* @return Number of data packets contained in the store after the operation
*/
void
populateStore(std::istream& is);
void
onRegisterFailed(const Name& prefix, const std::string& reason);
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
std::vector<shared_ptr<Data>> m_store;
private:
Name m_prefix;
Name m_versionedPrefix;
Face& m_face;
KeyChain& m_keyChain;
security::SigningInfo m_signingInfo;
time::milliseconds m_freshnessPeriod;
size_t m_maxSegmentSize;
bool m_isVerbose;
};
} // namespace chunks
} // namespace ndn
#endif // NDN_TOOLS_CHUNKS_PUTCHUNKS_PRODUCER_HPP
+30
View File
@@ -0,0 +1,30 @@
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
top = '../..'
def build(bld):
bld(features='cxx',
name='ndncatchunks-objects',
source=bld.path.ant_glob('catchunks/*.cpp', excl='catchunks/ndncatchunks.cpp'),
use='core-objects')
bld(features='cxx cxxprogram',
target='../../bin/ndncatchunks',
source='catchunks/ndncatchunks.cpp',
use='ndncatchunks-objects')
bld(features='cxx',
name='ndnputchunks-objects',
source=bld.path.ant_glob('putchunks/*.cpp', excl='putchunks/ndnputchunks.cpp'),
use='core-objects')
bld(features='cxx cxxprogram',
target='../../bin/ndnputchunks',
source='putchunks/ndnputchunks.cpp',
use='ndnputchunks-objects')
## (for unit tests)
bld(name='chunks-objects',
use='ndncatchunks-objects ndnputchunks-objects')
+107
View File
@@ -0,0 +1,107 @@
NDN Packet Dissector for Wireshark
==================================
**NDN packet dissector requires at least version 1.12.6 of Wireshark with LUA support enabled**
The dissection of [Named Data Networking (NDN) packets](http://named-data.net/doc/ndn-tlv/) is
supported in the following cases:
- NDN packets are encapsulated in IPv4/IPv6 UDP packets with source or destination port
6363 or 56363.
- NDN packets are encapsulated in IPv4/IPv6 TCP segments with source or destination
port 6363.
- NDN packets are encapsulated in IPv4/IPv6 TCP/HTTP WebSocket packets with source or
destination port 9696.
- NDN packets are encapsulated in Ethernet frames with EtherType 0x8624.
## Available dissection features
- When UDP packet is fragmented, the dissection is performed after the full IP reassembly.
If the full reassembly is not possible (e.g., a wrong checksum or missing segments),
dissection is not performed.
- When multiple NDN packets are part of a single UDP datagram, TCP segment, or WebSocket
payload, all NDN packets are dissected.
- When a single NDN packet is scattered across multiple TCP segments or WebSocket
payloads, it is dissected after the successful reconstruction of the necessary portion
of the TCP stream. If the reconstruction of the necessary portion of the TCP stream is
not possible (e.g., missing segments), the dissection is not performed.
- When an NDN packet is not aligned to the segment or payload boundary, the dissector
searches for any valid NDN packet within the segment using heuristics defined by the
following pseudocode:
for each offset in range (0, packet length)
type <- read TLV VarNumber from (buffer + offset)
length <- read TLV VarNumber from (buffer + offset + length of type field)
if type is either 5 or 6 // Type of NDN Interest of Data packet)
and length is less 8800 // Current (soft) limit for NDN packet size
then
dissect NDN packet from (buffer + offset)
end if
Currently, the dissector does not support NDNLPv2 packets.
## Usage
By default, the dissector script `ndn.lua` is installed into `/usr/local/share/ndn-dissect-wireshark`.
On some platforms, it may also be installed in `/usr/share/ndn-dissect-wireshark` or
`/opt/local/share/ndn-dissect-wireshark`. To enable the dissector for Wireshark session,
use `-X` command line option, specifying the full path to the `ndn.lua` script:
wireshark -X lua_script:/usr/local/share/ndn-dissect-wireshark/ndn.lua
Similarly, NDN packets dissector can be enabled when using `tshark`:
tshark shark -X lua_script:/usr/local/share/ndn-dissect-wireshark/ndn.lua
To enable NDN packets dissector for all future Wireshark sessions, you can create/edit
Wireshark's `init.lua` script, which located in `/usr/share/wireshark`,
`/usr/local/share/wireshark`, `/Applications/Wireshark.app/Contents/Resources/share/wireshark`,
or similar location depending on the platform and the way Wireshark is installed. The
`dofile` command should be added to the end of `init.lua` file:
-- dofile("/full/path/to/ndn.lua")
dofile("/usr/local/share/ndn-dissect-wireshark/ndn.lua")
For more detailed information about how to use Lua refer to [Lua wiki](https://wiki.wireshark.org/Lua).
## Known issues
Due to security issues, customized lua scripts are not allowed to be loaded when Wireshark
is started with root privileges. There are two workarounds:
- run Wireshark, `dumpcap`, or `tcpdump` with root privileges to capture traffic to a file, later
running Wireshark without root privileges and to analyze the captured traffic.
- (beware of potential security implications) allow non-root users to capture packets:
* On Linux platform, you can use `setcap`
sudo setcap cap_net_raw,cap_net_admin=eip /full/path/to/wireshark
You may need to install a package to use setcap (e.g., `sudo apt-get install libcap2-bin` on Ubuntu)
* On Debian/Ubuntu Linux, capturing traffic with Wireshark by a non-root user can be enabled by adding
this user to the `wireshark` group.
See [Wireshark Debian README](http://anonscm.debian.org/viewvc/collab-maint/ext-maint/wireshark/trunk/debian/README.Debian?view=markup)
for more details.
* On OSX platform, `/dev/bpf*` devices need to be assigned proper permissions
Automatically using ChmodBPF app
curl https://bugs.wireshark.org/bugzilla/attachment.cgi?id=3373 -o ChmodBPF.tar.gz
tar zxvf ChmodBPF.tar.gz
open ChmodBPF/Install\ ChmodBPF.app
or manually:
sudo chgrp admin /dev/bpf*
sudo chmod g+rw /dev/bpf*
+410
View File
@@ -0,0 +1,410 @@
-- Copyright (c) 2015, Regents of the University of California.
--
-- This file is part of ndn-tools (Named Data Networking Essential Tools).
-- See AUTHORS.md for complete list of ndn-tools authors and contributors.
--
-- ndn-tools is free software: you can redistribute it and/or modify it under the terms
-- of the GNU General Public License as published by the Free Software Foundation,
-- either version 3 of the License, or (at your option) any later version.
--
-- ndn-tools 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
-- ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
--
-- @author Qi Zhao <https://www.linkedin.com/pub/qi-zhao/73/835/9a3>
-- @author Seunghyun Yoo <http://relue2718.com/>
-- @author Seungbae Kim <https://sites.google.com/site/sbkimcv/>
-- @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
-- inspect.lua (https://github.com/kikito/inspect.lua) can be used for debugging.
-- See more at http://stackoverflow.com/q/15175859/2150331
-- local inspect = require('inspect')
-- NDN protocol
ndn = Proto("ndn", "Named Data Networking (NDN)")
-----------------------------------------------------
-----------------------------------------------------
-- Field formatting helpers
-- Borrowed from http://lua-users.org/wiki/StringRecipes
function escapeString(str)
if (str) then
str = string.gsub(str, "\n", "\r\n")
str = string.gsub(str, "([^%w %-%_%.%~])",
function (c) return string.format ("%%%02X", string.byte(c)) end)
str = string.gsub(str, " ", "+")
end
return str
end
function getUriFromNameComponent(block)
-- @todo Implement proper proper URL escaping
return block.tvb(block.offset + block.typeLen + block.lengthLen, block.length):string()
end
function getUriFromName(nameBlock)
if (nameBlock.elements == nil) then
return ""
else
components = {}
for i, block in pairs(nameBlock.elements) do
table.insert(components, getUriFromNameComponent(block))
end
return "/" .. table.concat(components, "/")
end
end
function getNonNegativeInteger(b)
if (b.length == 1) then
return b.tvb(b.offset + b.typeLen + b.lengthLen, 1):uint()
elseif (b.length == 2) then
return b.tvb(b.offset + b.typeLen + b.lengthLen, 2):uint()
elseif (b.length == 4) then
return b.tvb(b.offset + b.typeLen + b.lengthLen, 4):uint()
-- Something strange with uint64, not supporting it for now
-- elseif (b.length == 8) then
-- return b.tvb(b.offset + b.typeLen + b.lengthLen, 8):uint64()
else
return 0xFFFFFFFF;
end
end
function getUriFromExclude(block)
-- @todo
return ""
end
function getTrue(block)
return "Yes"
end
local AppPrivateBlock1 = 128
local AppPrivateBlock2 = 32767
function getGenericBlockInfo(block)
local name = ""
if (block.type < AppPrivateBlock1) then
name = "RESERVED_1"
elseif (AppPrivateBlock1 <= block.type and block.type < 253) then
name = "APP_TAG_1"
elseif (253 <= block.type and block.type < AppPrivateBlock2) then
name = "RESERVED_3"
else
name = "APP_TAG_3"
end
return name .. ", Type: " .. block.type .. ", Length: " .. block.length
end
-----------------------------------------------------
-----------------------------------------------------
local NDN_DICT = {
-- Interest or Data packets
[5] = {name = "Interest" , summary = true},
[6] = {name = "Data" , summary = true},
-- Name field
[7] = {name = "Name" , field = ProtoField.string("ndn.name", "Name") , value = getUriFromName},
[1] = {name = "ImplicitSha256DigestComponent", field = ProtoField.string("ndn.implicitsha256", "ImplicitSha256DigestComponent"), value = getUriFromNameComponent},
[8] = {name = "NameComponent" , field = ProtoField.string("ndn.namecomponent", "NameComponent") , value = getUriFromNameComponent},
-- Sub-fields of Interest packet
[9] = {name = "Selectors" , summary = true},
[10] = {name = "Nonce" , field = ProtoField.bytes("ndn.nonce", "Nonce")},
[12] = {name = "InterestLifetime" , field = ProtoField.uint32("ndn.interestlifetime", "InterestLifetime", base.DEC) , value = getNonNegativeInteger},
-- Sub-fields of Interest/Selector field
[13] = {name = "MinSuffixComponents" , field = ProtoField.uint32("ndn.minsuffix", "MinSuffixComponents") , value = getNonNegativeInteger},
[14] = {name = "MaxSuffixComponents" , field = ProtoField.uint32("ndn.maxsuffix", "MaxSuffixComponents") , value = getNonNegativeInteger},
[15] = {name = "PublisherPublicKeyLocator" , summary = true},
[16] = {name = "Exclude" , field = ProtoField.string("ndn.exclude", "Exclude") , value = getUriFromExclude},
[17] = {name = "ChildSelector" , field = ProtoField.uint32("ndn.childselector", "ChildSelector", base.DEC) , value = getNonNegativeInteger},
[18] = {name = "MustBeFresh" , field = ProtoField.string("ndn.mustbefresh", "MustBeFresh") , value = getTrue},
[19] = {name = "Any" , field = ProtoField.string("ndn.any", "Any") , value = getTrue},
-- Sub-fields of Data packet
[20] = {name = "MetaInfo" , summary = true},
[21] = {name = "Content" , field = ProtoField.string("ndn.content", "Content")},
[22] = {name = "SignatureInfo" , summary = true},
[23] = {name = "SignatureValue" , field = ProtoField.bytes("ndn.signaturevalue", "SignatureValue")},
-- Sub-fields of Data/MetaInfo field
[24] = {name = "ContentType" , field = ProtoField.uint32("ndn.contenttype", "Content Type", base.DEC) , value = getNonNegativeInteger},
[25] = {name = "FreshnessPeriod" , field = ProtoField.uint32("ndn.freshnessperiod", "FreshnessPeriod", base.DEC) , value = getNonNegativeInteger},
[26] = {name = "FinalBlockId" , field = ProtoField.string("ndn.finalblockid", "FinalBlockId") , value = getUriFromNameComponent},
-- Sub-fields of Data/Signature field
[27] = {name = "SignatureType" , field = ProtoField.uint32("ndn.signaturetype", "SignatureType", base.DEC) , value = getNonNegativeInteger},
[28] = {name = "KeyLocator" , summary = true},
[29] = {name = "KeyDigest" , field = ProtoField.bytes("ndn.keydigest", "KeyDigest")},
-- Other fields
[30] = {name = "LinkPreference" , field = ProtoField.uint32("ndn.link_preference", "LinkPreference", base.DEC) , value = getNonNegativeInteger},
[31] = {name = "LinkDelegation" , summary = true},
[32] = {name = "SelectedDelegation" , field = ProtoField.uint32("ndn.selected_delegation", "SelectedDelegation", base.DEC), value = getNonNegativeInteger},
}
-- -- Add protofields in NDN protocol
ndn.fields = {
}
for key, value in pairs(NDN_DICT) do
table.insert(ndn.fields, value.field)
end
-----------------------------------------------------
-----------------------------------------------------
-- block
-- .tvb
-- .offset
-- .type
-- .typeLen
-- .length
-- .lengthLen
-- .size = .typeLen + .lengthLen + .length
function addInfo(block, root) -- may be add additional context later
local info = NDN_DICT[block.type]
if (info == nil) then
info = {}
info.value = getGenericBlockInfo
end
local treeInfo
if (info.value == nil) then
if (info.field ~= nil) then
treeInfo = root:add(info.field, block.tvb(block.offset, block.size))
else
treeInfo = root:add(block.tvb(block.offset, block.size), info.name)
end
treeInfo:append_text(", Type: " .. block.type .. ", Length: " .. block.length)
else
block.value = info.value(block)
if (info.field ~= nil) then
treeInfo = root:add(info.field, block.tvb(block.offset, block.size), block.value)
else
treeInfo = root:add(block.tvb(block.offset, block.size), info.name)
end
end
block.root = treeInfo
return block.root
end
function addSummary(block)
if (block.elements == nil) then
return
end
local info = NDN_DICT[block.type]
if (info == nil or info.summary == nil) then
return
end
local summary = {}
for k, subblock in pairs(block.elements) do
if (subblock.value ~= nil) then
local info = NDN_DICT[subblock.type]
if (info ~= nil) then
table.insert(summary, info.name .. ": " .. subblock.value)
end
end
end
if (#summary > 0) then
block.summary = table.concat(summary, ", ")
if (block.value == nil) then
block.value = block.summary
end
block.root:append_text(", " .. block.summary)
end
end
-----------------------------------------------------
-----------------------------------------------------
function readVarNumber(tvb, offset)
local firstOctet = tvb(offset, 1):uint()
if (firstOctet < 253) then
return firstOctet, 1
elseif (firstOctet == 253) then
return tvb(offset + 1, 2):uint(), 3
elseif (firstOctet == 254) then
return tvb(offset + 1, 4):uint(), 5
elseif (firstOctet == 255) then
return tvb(offset + 1, 8):uint64(), 6
end
end
function getBlock(tvb, offset)
local block = {}
block.tvb = tvb
block.offset = offset
block.type, block.typeLen = readVarNumber(block.tvb, block.offset)
block.length, block.lengthLen = readVarNumber(block.tvb, block.offset + block.typeLen)
block.size = block.typeLen + block.lengthLen + block.length
return block
end
function canBeValidNdnPacket(block)
if ((block.type == 5 or block.type == 6) and block.length <= 8800) then
return true
else
return false
end
end
function findNdnPacket(tvb)
offset = 0
while offset + 2 < tvb:len() do
local block = getBlock(tvb, offset)
if canBeValidNdnPacket(block) then
return block
end
offset = offset + 1
end
return nil
end
function getSubBlocks(block)
local valueLeft = block.length
local subBlocks = {}
while valueLeft > 0 do
local child = getBlock(block.tvb,
block.offset + block.typeLen + block.lengthLen + (block.length - valueLeft))
valueLeft = valueLeft - child.size
table.insert(subBlocks, child)
end
if (valueLeft == 0) then
return subBlocks
else
return nil
end
end
-----------------------------------------------------
-----------------------------------------------------
-- NDN protocol dissector function
function ndn.dissector(tvb, pInfo, root) -- Tvb, Pinfo, TreeItem
if (tvb:len() ~= tvb:reported_len()) then
return 0 -- ignore partially captured packets
-- this can/may be re-enabled only for unfragmented UDP packets
end
local ok, block = pcall(findNdnPacket, tvb)
if (not ok) then
return 0
end
if (block == nil or block.offset == nil) then
-- no valid NDN packets found
return 0
end
local nBytesLeft = tvb:len() - block.offset
-- print (pInfo.number .. ":: Found block: " .. block.type .. " of length " .. block.size .. " bytesLeft: " .. nBytesLeft)
while (block.size <= nBytesLeft) do
-- Create TreeItems
block.tree = root:add(ndn, tvb(block.offset, block.size))
local queue = {block}
while (#queue > 0) do
local block = queue[1]
table.remove(queue, 1)
block.elements = getSubBlocks(block)
local subtree = addInfo(block, block.tree)
if (block.elements ~= nil) then
for i, subBlock in pairs(block.elements) do
subBlock.tree = subtree
table.insert(queue, subBlock)
end
end
end
-- Make summaries
local queue = {block}
while (#queue > 0) do
local block = queue[1]
if (block.visited ~= nil or block.elements == nil) then
-- try to make summary
table.remove(queue, 1)
addSummary(block)
else
for i, subBlock in pairs(block.elements) do
table.insert(queue, 1, subBlock)
end
block.visited = true
end
end
local info = NDN_DICT[block.type]
if (info ~= nil) then
block.tree:append_text(", " .. NDN_DICT[block.type].name .. ", " .. block.summary)
end
nBytesLeft = nBytesLeft - block.size
if (nBytesLeft > 0) then
ok, block = pcall(getBlock, tvb, tvb:len() - nBytesLeft)
if (not ok or not canBeValidNdnPacket(block)) then
break
end
end
end
pInfo.cols.protocol = tostring(pInfo.cols.protocol) .. " (" .. ndn.name .. ")"
if (nBytesLeft > 0 and block ~= nil and block.size ~= nil and block.size > nBytesLeft) then
pInfo.desegment_offset = tvb:len() - nBytesLeft
-- Originally, I set desegment_len to the exact lenght, but it mysteriously didn't work for TCP
-- pInfo.desegment_len = block.size -- this will not work to desegment TCP streams
pInfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT
end
end
local udpDissectorTable = DissectorTable.get("udp.port")
udpDissectorTable:add("6363", ndn)
udpDissectorTable:add("56363", ndn)
local tcpDissectorTable = DissectorTable.get("tcp.port")
tcpDissectorTable:add("6363", ndn)
local websocketDissectorTable = DissectorTable.get("ws.port")
-- websocketDissectorTable:add("9696", ndn)
websocketDissectorTable:add("1-65535", ndn)
local ethernetDissectorTable = DissectorTable.get("ethertype")
ethernetDissectorTable:add(0x8624, ndn)
io.stderr:write("ndn.lua is successfully loaded\n")
+5
View File
@@ -0,0 +1,5 @@
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
top = '../..'
def build(bld):
bld.install_files("${DATADIR}/ndn-dissect-wireshark", "ndn.lua")
+1 -1
View File
@@ -1,6 +1,6 @@
# ndndump
**ndndump** is a traffic analysis tool that captures Interest and Data packets on the wire,
**ndndump** is a traffic analysis tool that captures Interest, Data, and Nack packets on the wire
and displays brief information about captured packets.
Usage example:
+54 -13
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
* Copyright (c) 2014-2016, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
@@ -47,8 +47,8 @@ namespace dump {
#include "tcpdump/udp.h"
#include "tcpdump/tcp.h"
} // namespace ndn
} // namespace dump
} // namespace ndn
#include <boost/lexical_cast.hpp>
@@ -56,12 +56,12 @@ namespace dump {
#include <ndn-cxx/interest.hpp>
#include <ndn-cxx/data.hpp>
#include <ndn-cxx/lp/nack.hpp>
#include <ndn-cxx/lp/packet.hpp>
namespace ndn {
namespace dump {
// const uint8_t NDNLP_HEADER[] = {'N', 'd', 'n', 'l', 'p'};
const size_t MAX_SNAPLEN = 65535;
void
@@ -139,7 +139,7 @@ Ndndump::run()
void
Ndndump::onCapturedPacket(const struct pcap_pkthdr* header, const uint8_t* packet)
Ndndump::onCapturedPacket(const pcap_pkthdr* header, const uint8_t* packet)
{
std::ostringstream os;
printInterceptTime(os, header);
@@ -162,25 +162,66 @@ Ndndump::onCapturedPacket(const struct pcap_pkthdr* header, const uint8_t* packe
Block block;
std::tie(isOk, block) = Block::fromBuffer(payload, payloadSize);
if (!isOk) {
// if packet is fragmented, we will not be able to process it
// if packet is incomplete, we will not be able to process it
if (payloadSize > 0) {
std::cout << os.str() << ", " << "INCOMPLETE-PACKET" << ", size: " << payloadSize << std::endl;
}
return;
}
/// \todo Detect various header (LocalControlHeader, NDNLP, etc.)
lp::Packet lpPacket;
Block netPacket;
if (block.type() == lp::tlv::LpPacket) {
lpPacket = lp::Packet(block);
Buffer::const_iterator begin, end;
if (lpPacket.has<lp::FragmentField>()) {
std::tie(begin, end) = lpPacket.get<lp::FragmentField>();
}
else {
std::cout << os.str() << ", " << "NDNLPv2-IDLE" << std::endl;
return;
}
bool isOk = false;
std::tie(isOk, netPacket) = Block::fromBuffer(&*begin, std::distance(begin, end));
if (!isOk) {
// if network packet is fragmented, we will not be able to process it
std::cout << os.str() << ", " << "NDNLPv2-FRAGMENT" << std::endl;
return;
}
}
else {
netPacket = block;
}
try {
if (block.type() == tlv::Interest) {
Interest interest(block);
if (netPacket.type() == tlv::Interest) {
Interest interest(netPacket);
if (matchesFilter(interest.getName())) {
std::cout << os.str() << ", " << "INTEREST: " << interest << std::endl;
if (lpPacket.has<lp::NackField>()) {
lp::Nack nack(interest);
nack.setHeader(lpPacket.get<lp::NackField>());
std::cout << os.str() << ", " << "NACK: " << nack.getReason() << ", " << interest << std::endl;
}
else {
std::cout << os.str() << ", " << "INTEREST: " << interest << std::endl;
}
}
}
else if (block.type() == tlv::Data) {
Data data(block);
else if (netPacket.type() == tlv::Data) {
Data data(netPacket);
if (matchesFilter(data.getName())) {
std::cout << os.str() << ", " << "DATA: " << data.getName() << std::endl;
}
}
else {
std::cout << os.str() << ", " << "UNKNOWN-NETWORK-PACKET" << std::endl;
}
}
catch (tlv::Error& e) {
std::cerr << e.what() << std::endl;
@@ -188,7 +229,7 @@ Ndndump::onCapturedPacket(const struct pcap_pkthdr* header, const uint8_t* packe
}
void
Ndndump::printInterceptTime(std::ostream& os, const struct pcap_pkthdr* header)
Ndndump::printInterceptTime(std::ostream& os, const pcap_pkthdr* header)
{
os << header->ts.tv_sec
<< "."
+11 -6
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
* Copyright (c) 2014-2016, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
@@ -37,6 +37,8 @@
#ifndef NDN_TOOLS_DUMP_NDNDUMP_HPP
#define NDN_TOOLS_DUMP_NDNDUMP_HPP
#include "core/common.hpp"
#include <pcap.h>
#include <ndn-cxx/name.hpp>
@@ -72,18 +74,19 @@ public:
void
run();
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
void
onCapturedPacket(const pcap_pkthdr* header, const uint8_t* packet);
private:
static void
onCapturedPacket(uint8_t* userData, const struct pcap_pkthdr* header, const uint8_t* packet)
onCapturedPacket(uint8_t* userData, const pcap_pkthdr* header, const uint8_t* packet)
{
reinterpret_cast<Ndndump*>(userData)->onCapturedPacket(header, packet);
}
void
onCapturedPacket(const struct pcap_pkthdr* header, const uint8_t* packet);
void
printInterceptTime(std::ostream& os, const struct pcap_pkthdr* header);
printInterceptTime(std::ostream& os, const pcap_pkthdr* header);
int
skipDataLinkHeaderAndGetFrameType(const uint8_t*& payload, ssize_t& payloadSize);
@@ -120,6 +123,8 @@ public:
private:
pcap_t* m_pcap;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
int m_dataLinkType;
};
+131 -114
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Copyright (c) 2014-2016, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -49,6 +49,9 @@
*/
#include "core/version.hpp"
#include "core/common.hpp"
#include <ndn-cxx/util/io.hpp>
namespace ndn {
namespace peek {
@@ -58,55 +61,34 @@ class NdnPeek : boost::noncopyable
public:
explicit
NdnPeek(char* programName)
: m_programName(programName)
, m_mustBeFresh(false)
, m_isChildSelectorRightmost(false)
: isVerbose(false)
, mustBeFresh(false)
, wantRightmostChild(false)
, wantPayloadOnly(false)
, m_programName(programName)
, m_minSuffixComponents(-1)
, m_maxSuffixComponents(-1)
, m_interestLifetime(-1)
, m_isPayloadOnlySet(false)
, m_timeout(-1)
, m_prefixName("")
, m_isDataReceived(false)
, m_didReceiveData(false)
{
}
void
usage()
usage(std::ostream& os ,const boost::program_options::options_description& options) const
{
std::cout << "\n Usage:\n " << m_programName << " "
"[-f] [-r] [-m min] [-M max] [-l lifetime] [-p] [-w timeout] ndn:/name\n"
" Get one data item matching the name prefix and write it to stdout\n"
" [-f] - set MustBeFresh\n"
" [-r] - set ChildSelector to select rightmost child\n"
" [-m min] - set MinSuffixComponents\n"
" [-M max] - set MaxSuffixComponents\n"
" [-l lifetime] - set InterestLifetime in time::milliseconds\n"
" [-p] - print payload only, not full packet\n"
" [-w timeout] - set Timeout in time::milliseconds\n"
" [-h] - print help and exit\n"
" [-V] - print version and exit\n"
"\n";
exit(1);
}
void
setMustBeFresh()
{
m_mustBeFresh = true;
}
void
setRightmostChildSelector()
{
m_isChildSelectorRightmost = true;
os << "Usage: " << m_programName << " [options] ndn:/name\n"
" Fetch one data item matching the name prefix and write it to standard output\n"
"\n"
<< options;
}
void
setMinSuffixComponents(int minSuffixComponents)
{
if (minSuffixComponents < 0)
usage();
throw std::out_of_range("'minSuffixComponents' must be a non-negative integer");
m_minSuffixComponents = minSuffixComponents;
}
@@ -115,7 +97,7 @@ public:
setMaxSuffixComponents(int maxSuffixComponents)
{
if (maxSuffixComponents < 0)
usage();
throw std::out_of_range("'maxSuffixComponents' must be a non-negative integer");
m_maxSuffixComponents = maxSuffixComponents;
}
@@ -124,33 +106,32 @@ public:
setInterestLifetime(int interestLifetime)
{
if (interestLifetime < 0)
usage();
throw std::out_of_range("'lifetime' must be a non-negative integer");
m_interestLifetime = time::milliseconds(interestLifetime);
}
void
setPayloadOnly()
{
m_isPayloadOnlySet = true;
}
void
setTimeout(int timeout)
{
if (timeout < 0)
usage();
throw std::out_of_range("'timeout' must be a non-negative integer");
m_timeout = time::milliseconds(timeout);
}
void
setPrefixName(char* prefixName)
setLink(const std::string& file)
{
m_link = io::load<Link>(file);
if (m_link == nullptr)
throw std::runtime_error(file + " is either nonreadable or nonparseable");
}
void
setPrefixName(const std::string& prefixName)
{
m_prefixName = prefixName;
if (m_prefixName.length() == 0)
usage();
}
time::milliseconds
@@ -165,10 +146,10 @@ public:
Name interestName(m_prefixName);
Interest interestPacket(interestName);
if (m_mustBeFresh)
if (mustBeFresh)
interestPacket.setMustBeFresh(true);
if (m_isChildSelectorRightmost)
if (wantRightmostChild)
interestPacket.setChildSelector(1);
if (m_minSuffixComponents >= 0)
@@ -182,14 +163,28 @@ public:
else
interestPacket.setInterestLifetime(m_interestLifetime);
if (m_link != nullptr)
interestPacket.setLink(m_link->wireEncode());
if (isVerbose) {
std::cerr << "INTEREST: " << interestPacket << std::endl;
}
return interestPacket;
}
void
onData(const Interest& interest, Data& data)
{
m_isDataReceived = true;
if (m_isPayloadOnlySet) {
m_didReceiveData = true;
if (isVerbose) {
std::cerr << "DATA, RTT: "
<< time::duration_cast<time::milliseconds>(time::steady_clock::now() - m_expressInterestTime).count()
<< "ms" << std::endl;
}
if (wantPayloadOnly) {
const Block& block = data.getContent();
std::cout.write(reinterpret_cast<const char*>(block.value()), block.value_size());
}
@@ -204,45 +199,49 @@ public:
{
}
void
int
run()
{
try {
m_face.expressInterest(createInterestPacket(),
bind(&NdnPeek::onData, this, _1, _2),
bind(&NdnPeek::onTimeout, this, _1));
m_expressInterestTime = time::steady_clock::now();
if (m_timeout < time::milliseconds::zero()) {
if (m_interestLifetime < time::milliseconds::zero())
m_face.processEvents(getDefaultInterestLifetime());
else
m_face.processEvents(m_interestLifetime);
m_timeout = m_interestLifetime < time::milliseconds::zero() ?
getDefaultInterestLifetime() : m_interestLifetime;
}
else
m_face.processEvents(m_timeout);
m_face.processEvents(m_timeout);
}
catch (std::exception& e) {
std::cerr << "ERROR: " << e.what() << "\n" << std::endl;
exit(1);
catch (const std::exception& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
return 1;
}
if (isVerbose && !m_didReceiveData) {
std::cerr << "TIMEOUT" << std::endl;
return 3;
}
return 0;
}
bool
isDataReceived() const
{
return m_isDataReceived;
}
public:
bool isVerbose;
bool mustBeFresh;
bool wantRightmostChild;
bool wantPayloadOnly;
private:
std::string m_programName;
bool m_mustBeFresh;
bool m_isChildSelectorRightmost;
int m_minSuffixComponents;
int m_maxSuffixComponents;
time::milliseconds m_interestLifetime;
bool m_isPayloadOnlySet;
time::milliseconds m_timeout;
std::string m_prefixName;
bool m_isDataReceived;
time::steady_clock::TimePoint m_expressInterestTime;
shared_ptr<Link> m_link;
bool m_didReceiveData;
Face m_face;
};
@@ -250,55 +249,73 @@ int
main(int argc, char* argv[])
{
NdnPeek program(argv[0]);
int option;
while ((option = getopt(argc, argv, "hfrm:M:l:pw:V")) != -1) {
switch (option) {
case 'h':
program.usage();
break;
case 'f':
program.setMustBeFresh();
break;
case 'r':
program.setRightmostChildSelector();
break;
case 'm':
program.setMinSuffixComponents(atoi(optarg));
break;
case 'M':
program.setMaxSuffixComponents(atoi(optarg));
break;
case 'l':
program.setInterestLifetime(atoi(optarg));
break;
case 'p':
program.setPayloadOnly();
break;
case 'w':
program.setTimeout(atoi(optarg));
break;
case 'V':
namespace po = boost::program_options;
po::options_description visibleOptDesc("Allowed options");
visibleOptDesc.add_options()
("help,h", "print help and exit")
("version,V", "print version and exit")
("fresh,f", po::bool_switch(&program.mustBeFresh),
"set MustBeFresh")
("rightmost,r", po::bool_switch(&program.wantRightmostChild),
"set ChildSelector to rightmost")
("minsuffix,m", po::value<int>()->notifier(bind(&NdnPeek::setMinSuffixComponents, &program, _1)),
"set MinSuffixComponents")
("maxsuffix,M", po::value<int>()->notifier(bind(&NdnPeek::setMaxSuffixComponents, &program, _1)),
"set MaxSuffixComponents")
("lifetime,l", po::value<int>()->notifier(bind(&NdnPeek::setInterestLifetime, &program, _1)),
"set InterestLifetime (in milliseconds)")
("payload,p", po::bool_switch(&program.wantPayloadOnly),
"print payload only, instead of full packet")
("timeout,w", po::value<int>()->notifier(bind(&NdnPeek::setTimeout, &program, _1)),
"set timeout (in milliseconds)")
("verbose,v", po::bool_switch(&program.isVerbose),
"turn on verbose output")
("link-file", po::value<std::string>()->notifier(bind(&NdnPeek::setLink, &program, _1)),
"set Link from a file")
;
po::options_description hiddenOptDesc("Hidden options");
hiddenOptDesc.add_options()
("prefix", po::value<std::string>(), "Interest name");
po::options_description optDesc("Allowed options");
optDesc.add(visibleOptDesc).add(hiddenOptDesc);
po::positional_options_description optPos;
optPos.add("prefix", -1);
try {
po::variables_map vm;
po::store(po::command_line_parser(argc, argv).options(optDesc).positional(optPos).run(), vm);
po::notify(vm);
if (vm.count("help") > 0) {
program.usage(std::cout, visibleOptDesc);
return 0;
}
if (vm.count("version") > 0) {
std::cout << "ndnpeek " << tools::VERSION << std::endl;
return 0;
default:
program.usage();
break;
}
if (vm.count("prefix") > 0) {
std::string prefixName = vm["prefix"].as<std::string>();
program.setPrefixName(prefixName);
}
else {
throw std::runtime_error("Required argument 'prefix' is missing");
}
}
catch (const std::exception& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
program.usage(std::cerr, visibleOptDesc);
return 2;
}
argc -= optind;
argv += optind;
if (argv[0] == 0)
program.usage();
program.setPrefixName(argv[0]);
program.run();
if (program.isDataReceived())
return 0;
else
return 1;
return program.run();
}
} // namespace peek
+12
View File
@@ -0,0 +1,12 @@
# ndn-pib
**ndn-pib** is a service to manage the public information of keys (e.g., identity, public key, and
certificates). It provides a query interface to local applications for lookup and update this
information and also publishes certificates in the network.
Usage example:
1. start NFD on local machine
2. execute `ndn-pib [-h] -o username -d /database/dir -t tpm-locator`
For more information, consult the manpage.
+128
View File
@@ -0,0 +1,128 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "cert-publisher.hpp"
namespace ndn {
namespace pib {
CertPublisher::CertPublisher(Face& face, PibDb& db)
: m_face(face)
, m_db(db)
{
startPublishAll();
m_certDeletedConnection =
m_db.certificateDeleted.connect(bind(&CertPublisher::stopPublish, this, _1));
m_certInsertedConnection =
m_db.certificateInserted.connect(bind(&CertPublisher::startPublish, this, _1));
}
CertPublisher::~CertPublisher()
{
for (const auto& it : m_registeredPrefixes)
m_face.unsetInterestFilter(it.second);
}
void
CertPublisher::startPublishAll()
{
// For now we have to register the prefix of certificates separately.
// The reason is that certificates do not share the same prefix that
// can aggregate the certificates publishing without attracting interests
// for non-PIB data.
std::vector<Name> identities = m_db.listIdentities();
for (const auto& identity : identities) {
std::vector<Name> keyNames = m_db.listKeyNamesOfIdentity(identity);
for (const auto& key : keyNames) {
std::vector<Name> certNames = m_db.listCertNamesOfKey(key);
for (const auto& certName : certNames)
startPublish(certName);
}
}
}
void
CertPublisher::registerCertPrefix(const Name& certName)
{
BOOST_ASSERT(!certName.empty());
const Name& prefix = certName.getPrefix(-1);
if (m_registeredPrefixes.find(prefix) == m_registeredPrefixes.end()) {
m_registeredPrefixes[prefix] =
m_face.setInterestFilter(certName.getPrefix(-1),
bind(&CertPublisher::processInterest, this, _1, _2),
[] (const Name& name) {},
[=] (const Name& name, const std::string& msg) {
if (m_registeredPrefixes.erase(prefix) == 0) {
// registration no longer needed - certificates deleted
return;
}
// retry
registerCertPrefix(certName);
});
}
}
void
CertPublisher::processInterest(const InterestFilter& interestFilter,
const Interest& interest)
{
shared_ptr<const Data> certificate = m_responseCache.find(interest);
if (certificate != nullptr) {
m_face.put(*certificate);
}
}
void
CertPublisher::startPublish(const Name& certName)
{
m_responseCache.insert(*m_db.getCertificate(certName));
registerCertPrefix(certName);
}
void
CertPublisher::stopPublish(const Name& certName)
{
BOOST_ASSERT(!certName.empty());
m_responseCache.erase(certName);
// clear the listener if this is the only cert using the prefix
const Name& prefix = certName.getPrefix(-1); // strip version component
if (m_responseCache.find(prefix) != nullptr)
return;
auto it = m_registeredPrefixes.find(prefix);
BOOST_ASSERT(it != m_registeredPrefixes.end());
m_face.unsetInterestFilter(it->second);
m_registeredPrefixes.erase(it);
}
} // namespace pib
} // namespace ndn
+99
View File
@@ -0,0 +1,99 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#ifndef NDN_TOOLS_PIB_CERT_PUBLISHER_HPP
#define NDN_TOOLS_PIB_CERT_PUBLISHER_HPP
#include "pib-db.hpp"
#include <ndn-cxx/face.hpp>
#include <ndn-cxx/util/in-memory-storage-persistent.hpp>
namespace ndn {
namespace pib {
/// @brief implements the certificate publisher
class CertPublisher : noncopyable
{
public:
class Error : public std::runtime_error
{
public:
explicit
Error(const std::string& what)
: std::runtime_error(what)
{
}
};
/**
* @brief Constructor
*
* @param face The face pib used to receive queries and serve certificates.
* @param pibDb Database which holds the certificates.
*/
CertPublisher(Face& face, PibDb& pibDb);
~CertPublisher();
private:
void
startPublishAll();
/**
* @brief add an interest filter for the certificate
*/
void
registerCertPrefix(const Name& certName);
void
processInterest(const InterestFilter& interestFilter,
const Interest& interest);
void
startPublish(const Name& certName);
/**
* @brief callback when a certificate is deleted
*
* The method will remove the cert from in-memory storage
* and also unset interest filter if the removed cert
* is the only one with the registered prefix.
*
* @param certName removed certificate name
*/
void
stopPublish(const Name& certName);
private:
Face& m_face;
PibDb& m_db;
util::InMemoryStoragePersistent m_responseCache;
std::map<Name, const RegisteredPrefixId*> m_registeredPrefixes;
util::signal::ScopedConnection m_certDeletedConnection;
util::signal::ScopedConnection m_certInsertedConnection;
};
} // namespace pib
} // namespace ndn
#endif // NDN_TOOLS_PIB_CERT_PUBLISHER_HPP
+199
View File
@@ -0,0 +1,199 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "default-query-processor.hpp"
#include "encoding/pib-encoding.hpp"
#include <boost/lexical_cast.hpp>
namespace ndn {
namespace pib {
using std::string;
const size_t DefaultQueryProcessor::DEFAULT_QUERY_LENGTH = 5;
DefaultQueryProcessor::DefaultQueryProcessor(PibDb& db)
: m_db(db)
{
}
std::pair<bool, Block>
DefaultQueryProcessor::operator()(const Interest& interest)
{
const Name& interestName = interest.getName();
// handle pib query: /localhost/pib/[UserName]/default/param
if (interestName.size() != DEFAULT_QUERY_LENGTH) {
// malformed interest, discard
return std::make_pair(false, Block());
}
DefaultParam param;
try {
param.wireDecode(interestName.get(OFFSET_PARAM).blockFromValue());
}
catch (const tlv::Error& e) {
PibError error(ERR_WRONG_PARAM, "error in parsing param: " + string(e.what()));
return std::make_pair(true, error.wireEncode());
}
switch (param.getTargetType()) {
case TYPE_ID:
return processDefaultIdQuery(param);
case TYPE_KEY:
return processDefaultKeyQuery(param);
case TYPE_CERT:
return processDefaultCertQuery(param);
default:
{
PibError error(ERR_WRONG_PARAM,
"target type is not supported: " +
boost::lexical_cast<string>(param.getTargetType()));
return std::make_pair(true, error.wireEncode());
}
}
}
std::pair<bool, Block>
DefaultQueryProcessor::processDefaultIdQuery(const DefaultParam& param)
{
if (param.getOriginType() == TYPE_USER) {
try {
PibIdentity result(m_db.getDefaultIdentity());
return std::make_pair(true, result.wireEncode());
}
catch (PibDb::Error&) {
PibError error(ERR_NO_DEFAULT_ID, "default identity does not exist");
return std::make_pair(true, error.wireEncode());
}
}
else {
PibError error(ERR_WRONG_PARAM,
"origin type of id target must be USER(0), but gets: " +
boost::lexical_cast<string>(param.getOriginType()));
return std::make_pair(true, error.wireEncode());
}
}
std::pair<bool, Block>
DefaultQueryProcessor::processDefaultKeyQuery(const DefaultParam& param)
{
Name identity;
if (param.getOriginType() == TYPE_ID)
identity = param.getOriginName();
else if (param.getOriginType() == TYPE_USER) {
try {
identity = m_db.getDefaultIdentity();
}
catch (PibDb::Error&) {
PibError error(ERR_NO_DEFAULT_ID, "default identity does not exist");
return std::make_pair(true, error.wireEncode());
}
}
else {
PibError error(ERR_WRONG_PARAM,
"origin type of key target must be ID(1) or USER(0), but gets: " +
boost::lexical_cast<string>(param.getOriginType()));
return std::make_pair(true, error.wireEncode());
}
try {
Name keyName = m_db.getDefaultKeyNameOfIdentity(identity);
shared_ptr<PublicKey> key = m_db.getKey(keyName);
if (key == nullptr) {
PibError error(ERR_NO_DEFAULT_KEY, "default key does not exist");
return std::make_pair(true, error.wireEncode());
}
PibPublicKey result(keyName, *key);
return std::make_pair(true, result.wireEncode());
}
catch (PibDb::Error& e) {
PibError error(ERR_NO_DEFAULT_KEY,
"default key does not exist: " + string(e.what()));
return std::make_pair(true, error.wireEncode());
}
}
std::pair<bool, Block>
DefaultQueryProcessor::processDefaultCertQuery(const DefaultParam& param)
{
Name identity;
if (param.getOriginType() == TYPE_USER) {
try {
identity = m_db.getDefaultIdentity();
}
catch (PibDb::Error&) {
PibError error(ERR_NO_DEFAULT_ID, "default identity does not exist");
return std::make_pair(true, error.wireEncode());
}
}
else if (param.getOriginType() == TYPE_ID)
identity = param.getOriginName();
else if (param.getOriginType() != TYPE_KEY) {
PibError error(ERR_WRONG_PARAM,
"origin type of cert target must be KEY(2), ID(1) or USER(0), but gets: " +
boost::lexical_cast<string>(param.getOriginType()));
return std::make_pair(true, error.wireEncode());
}
Name keyName;
if (param.getOriginType() == TYPE_KEY) {
keyName = param.getOriginName();
if (keyName.size() < 1) {
PibError error(ERR_WRONG_PARAM,
"key name must contain key id component");
return std::make_pair(true, error.wireEncode());
}
}
else {
try {
keyName = m_db.getDefaultKeyNameOfIdentity(identity);
}
catch (PibDb::Error&) {
PibError error(ERR_NO_DEFAULT_KEY, "default key does not exist");
return std::make_pair(true, error.wireEncode());
}
}
try {
Name certName = m_db.getDefaultCertNameOfKey(keyName);
shared_ptr<IdentityCertificate> certificate = m_db.getCertificate(certName);
if (certificate == nullptr) {
PibError error (ERR_NO_DEFAULT_CERT, "default cert does not exist");
return std::make_pair(true, error.wireEncode());
}
PibCertificate result(*certificate);
return std::make_pair(true, result.wireEncode());
}
catch (PibDb::Error&) {
PibError error(ERR_NO_DEFAULT_CERT, "default cert does not exist");
return std::make_pair(true, error.wireEncode());
}
}
} // namespace pib
} // namespace ndn
+76
View File
@@ -0,0 +1,76 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#ifndef NDN_TOOLS_PIB_DEFAULT_QUERY_PROCESSOR_HPP
#define NDN_TOOLS_PIB_DEFAULT_QUERY_PROCESSOR_HPP
#include "pib-db.hpp"
#include "encoding/default-param.hpp"
#include <ndn-cxx/interest.hpp>
#include <utility>
namespace ndn {
namespace pib {
class DefaultQueryProcessor : noncopyable
{
public:
class Error : public std::runtime_error
{
public:
explicit
Error(const std::string& what)
: std::runtime_error(what)
{
}
};
/**
* @brief Constructor
*
* @param db The pib database.
*/
explicit
DefaultQueryProcessor(PibDb& db);
std::pair<bool, Block>
operator()(const Interest& interest);
private:
std::pair<bool, Block>
processDefaultIdQuery(const DefaultParam& param);
std::pair<bool, Block>
processDefaultKeyQuery(const DefaultParam& param);
std::pair<bool, Block>
processDefaultCertQuery(const DefaultParam& param);
private:
static const size_t DEFAULT_QUERY_LENGTH;
const PibDb& m_db;
};
} // namespace pib
} // namespace ndn
#endif // NDN_TOOLS_PIB_DEFAULT_QUERY_PROCESSOR_HPP
+205
View File
@@ -0,0 +1,205 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "delete-query-processor.hpp"
#include "encoding/pib-encoding.hpp"
#include "pib.hpp"
#include <boost/lexical_cast.hpp>
namespace ndn {
namespace pib {
using std::string;
const size_t DeleteQueryProcessor::DELETE_QUERY_LENGTH = 9;
const Name DeleteQueryProcessor::PIB_PREFIX("/localhost/pib");
DeleteQueryProcessor::DeleteQueryProcessor(PibDb& db)
: m_db(db)
{
}
std::pair<bool, Block>
DeleteQueryProcessor::operator()(const Interest& interest)
{
const Name& interestName = interest.getName();
// handle pib query: /localhost/pib/[UserName]/delete/param/<signed_interest_related_components>
if (interestName.size() != DELETE_QUERY_LENGTH) {
// malformed interest, discard
return std::make_pair(false, Block());
}
try {
DeleteParam param;
param.wireDecode(interestName.get(OFFSET_PARAM).blockFromValue());
SignatureInfo sigInfo;
sigInfo.wireDecode(interestName.get(OFFSET_SIG_INFO).blockFromValue());
// sigInfo must have KeyLocator.Name if the interest passed validation.
Name signerName;
signerName = sigInfo.getKeyLocator().getName();
switch (param.getTargetType()) {
case TYPE_USER:
return std::make_pair(true, PibError(ERR_WRONG_PARAM, "not allowed to delete user").wireEncode());
case TYPE_ID:
return processDeleteIdQuery(param, signerName);
case TYPE_KEY:
return processDeleteKeyQuery(param, signerName);
case TYPE_CERT:
return processDeleteCertQuery(param, signerName);
default:
{
PibError error(ERR_WRONG_PARAM,
"target type is not supported: " +
boost::lexical_cast<string>(param.getTargetType()));
return std::make_pair(true, error.wireEncode());
}
}
}
catch (const PibDb::Error& e) {
PibError error(ERR_INTERNAL_ERROR, e.what());
return std::make_pair(true, error.wireEncode());
}
catch (const tlv::Error& e) {
PibError error(ERR_WRONG_PARAM, "error in parsing param: " + string(e.what()));
return std::make_pair(true, error.wireEncode());
}
}
std::pair<bool, Block>
DeleteQueryProcessor::processDeleteIdQuery(const DeleteParam& param, const Name& signerName)
{
Name identity = param.getTargetName();
if (!isDeleteAllowed(TYPE_ID, identity, signerName)) {
PibError error(ERR_WRONG_SIGNER, "signer is not trusted for this command");
return std::make_pair(true, error.wireEncode());
}
m_db.deleteIdentity(identity);
return std::make_pair(true, PibError(ERR_SUCCESS).wireEncode());
}
std::pair<bool, Block>
DeleteQueryProcessor::processDeleteKeyQuery(const DeleteParam& param, const Name& signerName)
{
const Name& keyName = param.getTargetName();
if (!isDeleteAllowed(TYPE_KEY, keyName, signerName)) {
PibError error(ERR_WRONG_SIGNER, "signer is not trusted for this command");
return std::make_pair(true, error.wireEncode());
}
m_db.deleteKey(keyName);
return std::make_pair(true, PibError(ERR_SUCCESS).wireEncode());
}
std::pair<bool, Block>
DeleteQueryProcessor::processDeleteCertQuery(const DeleteParam& param, const Name& signerName)
{
const Name& certName = param.getTargetName();
if (!isDeleteAllowed(TYPE_CERT, certName, signerName)) {
PibError error(ERR_WRONG_SIGNER, "signer is not trusted for this command");
return std::make_pair(true, error.wireEncode());
}
m_db.deleteCertificate(certName);
return std::make_pair(true, PibError(ERR_SUCCESS).wireEncode());
}
bool
DeleteQueryProcessor::isDeleteAllowed(const pib::Type targetType,
const Name& targetName,
const Name& signer) const
{
// sanity checking, user cannot be deleted.
if (targetType == TYPE_USER)
return false;
// Any identity with prefix /localhost/pib is reserved. Any operation with a targetName under
// that prefix will be rejected.
if (PIB_PREFIX.isPrefixOf(targetName))
return false;
// Rules for other items:
//
// signer | deleting privilege
// =========================+===============================================
// local mgmt key | any id, key, and cert
// -------------------------+-----------------------------------------------
// default key of an id | any id, key, and cert under the id's namespace
// -------------------------+-----------------------------------------------
// non-default key of an id | any cert of the key
const Name& signerKeyName = IdentityCertificate::certificateNameToPublicKeyName(signer);
const Name& signerId = signerKeyName.getPrefix(-1);
bool hasSignerDefaultKey = true;
Name signerDefaultKeyName;
try {
signerDefaultKeyName = m_db.getDefaultKeyNameOfIdentity(signerId);
}
catch (PibDb::Error&) {
hasSignerDefaultKey = false;
}
Name mgmtCertName;
try {
mgmtCertName = m_db.getMgmtCertificate()->getName().getPrefix(-1);
}
catch (PibDb::Error&) {
return false;
}
if (signer == mgmtCertName) {
// signer is current management key, anything is allowed.
return true;
}
else if (hasSignerDefaultKey && signerDefaultKeyName == signerKeyName) {
// signer is an identity's default key
if (!signerId.isPrefixOf(targetName))
return false;
else
return true;
}
else {
// non-default key
if (targetType == TYPE_CERT) {
// check if it is for the key's cert
if (IdentityCertificate::certificateNameToPublicKeyName(targetName) == signerKeyName)
return true;
}
else if (targetType == TYPE_KEY) {
// check if it is for the key itself
if (targetName == signerKeyName)
return true;
}
return false;
}
}
} // namespace pib
} // namespace ndn
+93
View File
@@ -0,0 +1,93 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#ifndef NDN_TOOLS_PIB_DELETE_QUERY_PROCESSOR_HPP
#define NDN_TOOLS_PIB_DELETE_QUERY_PROCESSOR_HPP
#include "pib-db.hpp"
#include "encoding/delete-param.hpp"
#include <ndn-cxx/interest.hpp>
#include <utility>
namespace ndn {
namespace pib {
class Pib;
/// @brief Processing unit for PIB delete query
class DeleteQueryProcessor : noncopyable
{
public:
class Error : public std::runtime_error
{
public:
explicit
Error(const std::string& what)
: std::runtime_error(what)
{
}
};
/**
* @brief Constructor
*
* @param db The pib database.
*/
explicit
DeleteQueryProcessor(PibDb& db);
std::pair<bool, Block>
operator()(const Interest& interest);
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/**
* @brief Determine if a delete command is allowed.
*
* @param targetType The type of the target that will be deleted.
* @param targetName The name of the target that will be deleted.
* @param signer The name of the command signer.
*/
bool
isDeleteAllowed(const pib::Type targetType,
const Name& targetName,
const Name& signer) const;
private:
std::pair<bool, Block>
processDeleteIdQuery(const DeleteParam& param, const Name& signerName);
std::pair<bool, Block>
processDeleteKeyQuery(const DeleteParam& param, const Name& signerName);
std::pair<bool, Block>
processDeleteCertQuery(const DeleteParam& param, const Name& signerName);
private:
static const size_t DELETE_QUERY_LENGTH;
static const Name PIB_PREFIX;
PibDb& m_db;
};
} // namespace pib
} // namespace ndn
#endif // NDN_TOOLS_PIB_DELETE_QUERY_PROCESSOR_HPP
+168
View File
@@ -0,0 +1,168 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "default-param.hpp"
#include <ndn-cxx/encoding/block-helpers.hpp>
#include <boost/lexical_cast.hpp>
namespace ndn {
namespace pib {
static_assert(std::is_base_of<tlv::Error, DefaultParam::Error>::value,
"DefaultParam::Error must inherit from tlv::Error");
const std::string DefaultParam::VERB("default");
DefaultParam::DefaultParam()
: m_targetType(TYPE_DEFAULT)
, m_originType(TYPE_DEFAULT)
{
}
DefaultParam::DefaultParam(const pib::Type targetType,
const pib::Type originType,
const Name& originName)
: m_targetType(targetType)
, m_originType(originType)
, m_originName(originName)
{
}
DefaultParam::DefaultParam(const Block& wire)
{
wireDecode(wire);
}
const Name&
DefaultParam::getOriginName() const
{
if (m_originType == TYPE_ID || m_originType == TYPE_KEY || m_originType == TYPE_CERT)
return m_originName;
else
throw Error("DefaultParam::getOriginName: origin name does not exist");
}
template<bool T>
size_t
DefaultParam::wireEncode(EncodingImpl<T>& block) const
{
size_t totalLength = 0;
switch (m_originType) {
case TYPE_ID:
case TYPE_KEY:
case TYPE_CERT:
{
totalLength += m_originName.wireEncode(block);
break;
}
case TYPE_USER:
break;
default:
throw Error("DefaultParam::wireEncode: unsupported PibType: " +
boost::lexical_cast<std::string>(m_originType));
}
totalLength += prependNonNegativeIntegerBlock(block, tlv::pib::Type, m_originType);
totalLength += prependNonNegativeIntegerBlock(block, tlv::pib::Type, m_targetType);
totalLength += block.prependVarNumber(totalLength);
totalLength += block.prependVarNumber(tlv::pib::DefaultParam);
return totalLength;
}
template size_t
DefaultParam::wireEncode<true>(EncodingImpl<true>& block) const;
template size_t
DefaultParam::wireEncode<false>(EncodingImpl<false>& block) const;
const Block&
DefaultParam::wireEncode() const
{
if (m_wire.hasWire())
return m_wire;
EncodingEstimator estimator;
size_t estimatedSize = wireEncode(estimator);
EncodingBuffer buffer(estimatedSize, 0);
wireEncode(buffer);
m_wire = buffer.block();
return m_wire;
}
void
DefaultParam::wireDecode(const Block& wire)
{
if (!wire.hasWire()) {
throw Error("The supplied block does not contain wire format");
}
m_wire = wire;
m_wire.parse();
if (m_wire.type() != tlv::pib::DefaultParam)
throw Error("Unexpected TLV type when decoding DefaultParam");
Block::element_const_iterator it = m_wire.elements_begin();
// the first block must be PibType
if (it != m_wire.elements_end() && it->type() == tlv::pib::Type) {
m_targetType = static_cast<pib::Type>(readNonNegativeInteger(*it));
it++;
}
else
throw Error("DefaultParam requires the first sub-TLV to be PibType");
// the second block must be PibType
if (it != m_wire.elements_end() && it->type() == tlv::pib::Type) {
m_originType = static_cast<pib::Type>(readNonNegativeInteger(*it));
it++;
}
else
throw Error("DefaultParam requires the second sub-TLV to be PibType");
switch (m_originType) {
case TYPE_ID:
case TYPE_KEY:
case TYPE_CERT:
{
if (it != m_wire.elements_end()) {
// the third block, if exists, must be Name
m_originName.wireDecode(*it);
return;
}
else {
throw Error("DefaultParam requires the third sub-TLV to be Name");
}
}
case TYPE_USER:
return;
default:
throw Error("DefaultParam::wireDecode: unsupported PibType: " +
boost::lexical_cast<std::string>(m_originType));
}
}
} // namespace pib
} // namespace ndn
+127
View File
@@ -0,0 +1,127 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#ifndef NDN_TOOLS_PIB_DEFAULT_PARAM_HPP
#define NDN_TOOLS_PIB_DEFAULT_PARAM_HPP
#include "pib-common.hpp"
#include <ndn-cxx/name.hpp>
namespace ndn {
namespace pib {
/**
* @brief DefaultParam is the abstraction of PIB Default parameter.
*
* PibDefaultParam := PIB-DEFAULT-PARAM-TYPE TLV-LENGTH
* PibType // target type
* PibType // origin type
* Name? // origin name
*
* @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Default-Parameters
*/
class DefaultParam : noncopyable
{
public:
class Error : public tlv::Error
{
public:
explicit
Error(const std::string& what)
: tlv::Error(what)
{
}
};
DefaultParam();
DefaultParam(const pib::Type targetType,
const pib::Type originType,
const Name& originName = Name());
explicit
DefaultParam(const Block& wire);
tlv::pib::ParamType
getParamType() const
{
return tlv::pib::DefaultParam;
}
pib::Type
getTargetType() const
{
return m_targetType;
}
pib::Type
getOriginType() const
{
return m_originType;
}
/**
* @brief Get target name
*
* @throws Error if origin name does not exist
*/
const Name&
getOriginName() const;
/// @brief Encode to a wire format or estimate wire format
template<bool T>
size_t
wireEncode(EncodingImpl<T>& block) const;
/**
* @brief Encode to a wire format
*
* @throws Error if encoding fails
*/
const Block&
wireEncode() const;
/**
* @brief Decode GetParam from a wire encoded block
*
* @throws Error if decoding fails
*/
void
wireDecode(const Block& wire);
public:
static const std::string VERB;
private:
pib::Type m_targetType;
pib::Type m_originType;
Name m_originName;
mutable Block m_wire;
};
} // namespace pib
} // namespace ndn
#endif // NDN_TOOLS_PIB_DEFAULT_PARAM_HPP
+129
View File
@@ -0,0 +1,129 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "delete-param.hpp"
#include <ndn-cxx/encoding/block-helpers.hpp>
#include <boost/lexical_cast.hpp>
namespace ndn {
namespace pib {
static_assert(std::is_base_of<tlv::Error, DeleteParam::Error>::value,
"DeleteParam::Error must inherit from tlv::Error");
const std::string DeleteParam::VERB("delete");
DeleteParam::DeleteParam()
: m_targetType(TYPE_DEFAULT)
{
}
DeleteParam::DeleteParam(const Name& name, pib::Type type)
: m_targetType(type)
, m_targetName(name)
{
}
DeleteParam::DeleteParam(const Block& wire)
{
wireDecode(wire);
}
template<bool T>
size_t
DeleteParam::wireEncode(EncodingImpl<T>& block) const
{
if (m_targetType != TYPE_ID &&
m_targetType != TYPE_KEY &&
m_targetType != TYPE_CERT &&
m_targetType != TYPE_USER)
throw Error("DeleteParam::wireEncode: Wrong Type value: " +
boost::lexical_cast<std::string>(m_targetType));
size_t totalLength = 0;
totalLength += m_targetName.wireEncode(block);
totalLength += prependNonNegativeIntegerBlock(block, tlv::pib::Type, m_targetType);
totalLength += block.prependVarNumber(totalLength);
totalLength += block.prependVarNumber(tlv::pib::DeleteParam);
return totalLength;
}
template size_t
DeleteParam::wireEncode<true>(EncodingImpl<true>& block) const;
template size_t
DeleteParam::wireEncode<false>(EncodingImpl<false>& block) const;
const Block&
DeleteParam::wireEncode() const
{
if (m_wire.hasWire())
return m_wire;
EncodingEstimator estimator;
size_t estimatedSize = wireEncode(estimator);
EncodingBuffer buffer(estimatedSize, 0);
wireEncode(buffer);
m_wire = buffer.block();
return m_wire;
}
void
DeleteParam::wireDecode(const Block& wire)
{
if (!wire.hasWire()) {
throw Error("The supplied block does not contain wire format");
}
m_wire = wire;
m_wire.parse();
if (m_wire.type() != tlv::pib::DeleteParam)
throw Error("Unexpected TLV type when decoding DeleteParam");
Block::element_const_iterator it = m_wire.elements_begin();
// the first block must be Type
if (it != m_wire.elements_end() && it->type() == tlv::pib::Type) {
m_targetType = static_cast<pib::Type>(readNonNegativeInteger(*it));
it++;
}
else
throw Error("DeleteParam requires the first sub-TLV to be Type");
// the second block must be Name
if (it != m_wire.elements_end() && it->type() == tlv::Name) {
m_targetName.wireDecode(*it);
it++;
}
else
throw Error("DeleteParam requires the second sub-TLV to be Name");
if (it != m_wire.elements_end())
throw Error("DeleteParam must not contain more than two sub-TLVs");
}
} // namespace pib
} // namespace ndn
+114
View File
@@ -0,0 +1,114 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#ifndef NDN_TOOLS_PIB_DELETE_PARAM_HPP
#define NDN_TOOLS_PIB_DELETE_PARAM_HPP
#include "pib-common.hpp"
#include <ndn-cxx/name.hpp>
namespace ndn {
namespace pib {
/**
* @brief DeleteParam is the abstraction of PIB Delete parameter.
*
* PibDeleteParam := PIB-DELETE-PARAM-TYPE TLV-LENGTH
* PibType
* Name
*
* @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Delete-Parameters
*/
class DeleteParam : noncopyable
{
public:
class Error : public tlv::Error
{
public:
explicit
Error(const std::string& what)
: tlv::Error(what)
{
}
};
DeleteParam();
explicit
DeleteParam(const Name& name, const pib::Type type = TYPE_ID);
explicit
DeleteParam(const Block& wire);
tlv::pib::ParamType
getParamType() const
{
return tlv::pib::DeleteParam;
}
pib::Type
getTargetType() const
{
return m_targetType;
}
const Name&
getTargetName() const
{
return m_targetName;
}
/// @brief Encode to a wire format or estimate wire format
template<bool T>
size_t
wireEncode(EncodingImpl<T>& block) const;
/**
* @brief Encode to a wire format
*
* @throws Error if encoding fails
*/
const Block&
wireEncode() const;
/**
* @brief Decode GetParam from a wire encoded block
*
* @throws Error if decoding fails
*/
void
wireDecode(const Block& wire);
public:
static const std::string VERB;
private:
pib::Type m_targetType;
Name m_targetName;
mutable Block m_wire;
};
} // namespace pib
} // namespace ndn
#endif // NDN_TOOLS_PIB_DELETE_PARAM_HPP
+156
View File
@@ -0,0 +1,156 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "get-param.hpp"
#include <boost/lexical_cast.hpp>
#include <ndn-cxx/encoding/block-helpers.hpp>
namespace ndn {
namespace pib {
static_assert(std::is_base_of<tlv::Error, GetParam::Error>::value,
"GetParam::Error must inherit from tlv::Error");
const std::string GetParam::VERB("get");
GetParam::GetParam()
: m_targetType(TYPE_USER)
{
}
GetParam::GetParam(const pib::Type targetType, const Name& targetName)
: m_targetType(targetType)
, m_targetName(targetName)
{
}
GetParam::GetParam(const Block& wire)
{
wireDecode(wire);
}
const Name&
GetParam::getTargetName() const
{
if (m_targetType == TYPE_ID || m_targetType == TYPE_KEY || m_targetType == TYPE_CERT)
return m_targetName;
else
throw Error("GetParam::getTargetName: target name does not exist");
}
template<bool T>
size_t
GetParam::wireEncode(EncodingImpl<T>& block) const
{
size_t totalLength = 0;
switch (m_targetType) {
case TYPE_ID:
case TYPE_KEY:
case TYPE_CERT:
{
totalLength += m_targetName.wireEncode(block);
break;
}
case TYPE_USER:
break;
default:
throw Error("GetParam::wireEncode: unsupported PibType: " +
boost::lexical_cast<std::string>(m_targetType));
}
// Encode Type
totalLength += prependNonNegativeIntegerBlock(block, tlv::pib::Type, m_targetType);
totalLength += block.prependVarNumber(totalLength);
totalLength += block.prependVarNumber(tlv::pib::GetParam);
return totalLength;
}
template size_t
GetParam::wireEncode<true>(EncodingImpl<true>& block) const;
template size_t
GetParam::wireEncode<false>(EncodingImpl<false>& block) const;
const Block&
GetParam::wireEncode() const
{
if (m_wire.hasWire())
return m_wire;
EncodingEstimator estimator;
size_t estimatedSize = wireEncode(estimator);
EncodingBuffer buffer(estimatedSize, 0);
wireEncode(buffer);
m_wire = buffer.block();
return m_wire;
}
void
GetParam::wireDecode(const Block& wire)
{
if (!wire.hasWire()) {
throw Error("The supplied block does not contain wire format");
}
m_wire = wire;
m_wire.parse();
if (m_wire.type() != tlv::pib::GetParam)
throw Error("Unexpected TLV type when decoding GetParam");
Block::element_const_iterator it = m_wire.elements_begin();
// the first block must be Type
if (it != m_wire.elements_end() && it->type() == tlv::pib::Type) {
m_targetType = static_cast<pib::Type>(readNonNegativeInteger(*it));
it++;
}
else
throw Error("GetParam requires the first sub-TLV to be PibType");
switch (m_targetType) {
case TYPE_ID:
case TYPE_KEY:
case TYPE_CERT:
{
if (it != m_wire.elements_end()) {
// the second block, if exists, must be Name
m_targetName.wireDecode(*it);
return;
}
else {
throw Error("GetParam requires the second sub-TLV to be Name");
}
}
case TYPE_USER:
return;
default:
throw Error("GetParam::wireDecode: unsupported PibType: " +
boost::lexical_cast<std::string>(m_targetType));
}
}
} // namespace pib
} // namespace ndn
+115
View File
@@ -0,0 +1,115 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#ifndef NDN_TOOLS_PIB_GET_PARAM_HPP
#define NDN_TOOLS_PIB_GET_PARAM_HPP
#include "pib-common.hpp"
#include <ndn-cxx/name.hpp>
namespace ndn {
namespace pib {
/**
* @brief GetParam is the abstraction of PIB Get parameter.
*
* PibGetParam := PIB-GET-PARAM-TYPE TLV-LENGTH
* PibType
* Name?
*
* @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Get-Parameters
*/
class GetParam : noncopyable
{
public:
class Error : public tlv::Error
{
public:
explicit
Error(const std::string& what)
: tlv::Error(what)
{
}
};
GetParam();
GetParam(const pib::Type targetType, const Name& targetName);
explicit
GetParam(const Block& wire);
tlv::pib::ParamType
getParamType() const
{
return tlv::pib::GetParam;
}
pib::Type
getTargetType() const
{
return m_targetType;
}
/**
* @brief Get target name
*
* @throws Error if target name does not exist
*/
const Name&
getTargetName() const;
/// @brief Encode to a wire format or estimate wire format
template<bool T>
size_t
wireEncode(EncodingImpl<T>& block) const;
/**
* @brief Encode to a wire format
*
* @throws Error if encoding fails
*/
const Block&
wireEncode() const;
/**
* @brief Decode GetParam from a wire encoded block
*
* @throws Error if decoding fails
*/
void
wireDecode(const Block& wire);
public:
static const std::string VERB;
private:
pib::Type m_targetType;
Name m_targetName;
mutable Block m_wire;
};
} // namespace pib
} // namespace ndn
#endif // NDN_TOOLS_PIB_GET_PARAM_HPP
+155
View File
@@ -0,0 +1,155 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "list-param.hpp"
#include <ndn-cxx/encoding/block-helpers.hpp>
#include <boost/lexical_cast.hpp>
namespace ndn {
namespace pib {
static_assert(std::is_base_of<tlv::Error, ListParam::Error>::value,
"ListParam::Error must inherit from tlv::Error");
const std::string ListParam::VERB("list");
ListParam::ListParam()
: m_originType(TYPE_USER)
{
}
ListParam::ListParam(const pib::Type originType, const Name& originName)
: m_originType(originType)
, m_originName(originName)
{
}
ListParam::ListParam(const Block& wire)
{
wireDecode(wire);
}
const Name&
ListParam::getOriginName() const
{
if (m_originType == TYPE_ID || m_originType == TYPE_KEY || m_originType == TYPE_CERT)
return m_originName;
else
throw Error("ListParam::getOriginName: origin name does not exist");
}
template<bool T>
size_t
ListParam::wireEncode(EncodingImpl<T>& block) const
{
size_t totalLength = 0;
switch (m_originType) {
case TYPE_ID:
case TYPE_KEY:
case TYPE_CERT:
{
totalLength += m_originName.wireEncode(block);
break;
}
case TYPE_USER:
break;
default:
throw Error("ListParam::wireEncode: unsupported PibType: " +
boost::lexical_cast<std::string>(m_originType));
}
totalLength += prependNonNegativeIntegerBlock(block, tlv::pib::Type, m_originType);
totalLength += block.prependVarNumber(totalLength);
totalLength += block.prependVarNumber(tlv::pib::ListParam);
return totalLength;
}
template size_t
ListParam::wireEncode<true>(EncodingImpl<true>& block) const;
template size_t
ListParam::wireEncode<false>(EncodingImpl<false>& block) const;
const Block&
ListParam::wireEncode() const
{
if (m_wire.hasWire())
return m_wire;
EncodingEstimator estimator;
size_t estimatedSize = wireEncode(estimator);
EncodingBuffer buffer(estimatedSize, 0);
wireEncode(buffer);
m_wire = buffer.block();
return m_wire;
}
void
ListParam::wireDecode(const Block& wire)
{
if (!wire.hasWire()) {
throw Error("The supplied block does not contain wire format");
}
m_wire = wire;
m_wire.parse();
if (m_wire.type() != tlv::pib::ListParam)
throw Error("Unexpected TLV type when decoding ListParam");
Block::element_const_iterator it = m_wire.elements_begin();
// the first block must be PibType
if (it != m_wire.elements_end() && it->type() == tlv::pib::Type) {
m_originType = static_cast<pib::Type>(readNonNegativeInteger(*it));
it++;
}
else
throw Error("ListParam requires the first sub-TLV to be PibType");
switch (m_originType) {
case TYPE_ID:
case TYPE_KEY:
case TYPE_CERT:
{
if (it != m_wire.elements_end()) {
// the second block, if exists, must be Name
m_originName.wireDecode(*it);
return;
}
else {
throw Error("ListParam requires the second sub-TLV to be Name");
}
}
case TYPE_USER:
return;
default:
throw Error("ListParam::wireDecode: unsupported PibType: " +
boost::lexical_cast<std::string>(m_originType));
}
}
} // namespace pib
} // namespace ndn
+117
View File
@@ -0,0 +1,117 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#ifndef NDN_TOOLS_PIB_LIST_PARAM_HPP
#define NDN_TOOLS_PIB_LIST_PARAM_HPP
#include "pib-common.hpp"
#include <ndn-cxx/name.hpp>
namespace ndn {
namespace pib {
/**
* @brief ListParam is the abstraction of PIB List parameter.
*
* PibListParam := PIB-LIST-PARAM-TYPE TLV-LENGTH
* PibType // origin type
* Name? // origin name
*
* @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#List-Parameters
*/
class ListParam : noncopyable
{
public:
class Error : public tlv::Error
{
public:
explicit
Error(const std::string& what)
: tlv::Error(what)
{
}
};
ListParam();
ListParam(const pib::Type originType, const Name& originName);
explicit
ListParam(const Block& wire);
tlv::pib::ParamType
getParamType() const
{
return tlv::pib::ListParam;
}
pib::Type
getOriginType() const
{
return m_originType;
}
/**
* @brief Get target name
*
* @throws Error if origin name does not exist
*/
const Name&
getOriginName() const;
/// @brief Encode to a wire format or estimate wire format
template<bool T>
size_t
wireEncode(EncodingImpl<T>& block) const;
/**
* @brief Encode to a wire format
*
* @throws Error if encoding fails
*/
const Block&
wireEncode() const;
/**
* @brief Decode GetParam from a wire encoded block
*
* @throws Error if decoding fails
*/
void
wireDecode(const Block& wire);
public:
static const std::string VERB;
private:
pib::Type m_originType;
Name m_originName;
mutable Block m_wire;
};
} // namespace pib
} // namespace ndn
#endif // NDN_TOOLS_PIB_LIST_PARAM_HPP
+128
View File
@@ -0,0 +1,128 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#ifndef NDN_TOOLS_PIB_PIB_COMMON_HPP
#define NDN_TOOLS_PIB_PIB_COMMON_HPP
namespace ndn {
namespace pib {
/// @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base
enum {
OFFSET_USER = 2,
OFFSET_VERB = 3,
OFFSET_PARAM = 4,
OFFSET_TIMESTAMP = 5,
OFFSET_NONCE = 6,
OFFSET_SIG_INFO = 7,
OFFSET_SIG_VALUE = 8,
MIN_PIB_INTEREST_SIZE = 5,
SIGNED_PIB_INTEREST_SIZE = 9
};
enum Type {
TYPE_USER = 0,
TYPE_ID = 1,
TYPE_KEY = 2,
TYPE_CERT = 3,
TYPE_DEFAULT = 255
};
enum DefaultOpt {
DEFAULT_OPT_NO = 0,
DEFAULT_OPT_KEY = 1, // 0x01
DEFAULT_OPT_ID = 3, // 0x03
DEFAULT_OPT_USER = 7 // 0x07
};
enum DefaultOptMask {
DEFAULT_OPT_KEY_MASK = 0x1,
DEFAULT_OPT_ID_MASK = 0x2,
DEFAULT_OPT_USER_MASK = 0x4
};
enum ErrCode {
ERR_SUCCESS = 0,
// Invalid query
ERR_INCOMPLETE_COMMAND = 1,
ERR_WRONG_VERB = 2,
ERR_WRONG_PARAM = 3,
ERR_WRONG_SIGNER = 4,
ERR_INTERNAL_ERROR = 5,
// Non existing entity
ERR_NON_EXISTING_USER = 128,
ERR_NON_EXISTING_ID = 129,
ERR_NON_EXISTING_KEY = 130,
ERR_NON_EXISTING_CERT = 131,
// No default setting
ERR_NO_DEFAULT_ID = 256,
ERR_NO_DEFAULT_KEY = 257,
ERR_NO_DEFAULT_CERT = 258,
// Delete default setting
ERR_DELETE_DEFAULT_SETTING = 384
};
} // namespace pib
namespace tlv {
namespace pib {
enum ParamType {
GetParam = 128, // 0x80
DefaultParam = 129, // 0x81
ListParam = 130, // 0x82
UpdateParam = 131, // 0x83
DeleteParam = 132 // 0x84
};
enum EntityType {
User = 144, // 0x90
Identity = 145, // 0x91
PublicKey = 146, // 0x92
Certificate = 147 // 0x93
};
// Other
enum {
Bytes = 148, // 0x94
DefaultOpt = 149, // 0x95
NameList = 150, // 0x96
Type = 151, // 0x97
Error = 152, // 0x98
TpmLocator = 153, // 0x99
// ErrorCode
ErrorCode = 252 // 0xfc
};
} // namespace pib
} // namespace tlv
} // namespace ndn
#endif // NDN_TOOLS_PIB_PIB_COMMON_HPP
+525
View File
@@ -0,0 +1,525 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "pib-encoding.hpp"
#include <ndn-cxx/encoding/block-helpers.hpp>
#include <ndn-cxx/encoding/encoding-buffer.hpp>
#include <vector>
#include <string>
namespace ndn {
namespace pib {
using std::vector;
using std::string;
PibIdentity::PibIdentity()
{
}
PibIdentity::PibIdentity(const Name& identity)
: m_identity(identity)
{
}
PibIdentity::PibIdentity(const Block& wire)
{
wireDecode(wire);
}
template<bool T>
size_t
PibIdentity::wireEncode(EncodingImpl<T>& block) const
{
size_t totalLength = m_identity.wireEncode(block);
totalLength += block.prependVarNumber(totalLength);
totalLength += block.prependVarNumber(tlv::pib::Identity);
return totalLength;
}
template size_t
PibIdentity::wireEncode<true>(EncodingImpl<true>& block) const;
template size_t
PibIdentity::wireEncode<false>(EncodingImpl<false>& block) const;
const Block&
PibIdentity::wireEncode() const
{
if (m_wire.hasWire())
return m_wire;
EncodingEstimator estimator;
size_t estimatedSize = wireEncode(estimator);
EncodingBuffer buffer(estimatedSize, 0);
wireEncode(buffer);
m_wire = buffer.block();
return m_wire;
}
void
PibIdentity::wireDecode(const Block& wire)
{
if (!wire.hasWire()) {
throw tlv::Error("The supplied block does not contain wire format");
}
if (wire.type() != tlv::pib::Identity)
throw tlv::Error("Unexpected TLV type when decoding PibIdentity");
m_wire = wire;
m_identity.wireDecode(m_wire.blockFromValue());
}
PibPublicKey::PibPublicKey()
: m_isValueSet(false)
{
}
PibPublicKey::PibPublicKey(const Name& keyName, const PublicKey& key)
: m_isValueSet(true)
, m_keyName(keyName)
, m_key(key)
{
}
PibPublicKey::PibPublicKey(const Block& wire)
{
wireDecode(wire);
}
const Name&
PibPublicKey::getKeyName() const
{
if (m_isValueSet)
return m_keyName;
else
throw tlv::Error("PibPublicKey::getKeyName: keyName is not set");
}
const PublicKey&
PibPublicKey::getPublicKey() const
{
if (m_isValueSet)
return m_key;
else
throw tlv::Error("PibPublicKey::getPublicKey: key is not set");
}
template<bool T>
size_t
PibPublicKey::wireEncode(EncodingImpl<T>& block) const
{
size_t totalLength = prependByteArrayBlock(block, tlv::pib::Bytes,
m_key.get().buf(), m_key.get().size());
totalLength += m_keyName.wireEncode(block);
totalLength += block.prependVarNumber(totalLength);
totalLength += block.prependVarNumber(tlv::pib::PublicKey);
return totalLength;
}
template size_t
PibPublicKey::wireEncode<true>(EncodingImpl<true>& block) const;
template size_t
PibPublicKey::wireEncode<false>(EncodingImpl<false>& block) const;
const Block&
PibPublicKey::wireEncode() const
{
if (m_wire.hasWire())
return m_wire;
EncodingEstimator estimator;
size_t estimatedSize = wireEncode(estimator);
EncodingBuffer buffer(estimatedSize, 0);
wireEncode(buffer);
m_wire = buffer.block();
return m_wire;
}
void
PibPublicKey::wireDecode(const Block& wire)
{
if (!wire.hasWire()) {
throw tlv::Error("The supplied block does not contain wire format");
}
if (wire.type() != tlv::pib::PublicKey)
throw tlv::Error("Unexpected TLV type when decoding PibPublicKey");
m_wire = wire;
m_wire.parse();
Block::element_const_iterator it = m_wire.elements_begin();
if (it != m_wire.elements_end() && it->type() == tlv::Name) {
m_keyName.wireDecode(*it);
it++;
}
else
throw tlv::Error("PibPublicKey requires the first sub-TLV to be Name");
if (it != m_wire.elements_end() && it->type() == tlv::pib::Bytes) {
m_key = PublicKey(it->value(), it->value_size());
it++;
}
else
throw tlv::Error("PibPublicKey requires the second sub-TLV to be Bytes");
m_isValueSet = true;
if (it != m_wire.elements_end())
throw tlv::Error("PibPublicKey must contain only two sub-TLVs");
}
PibCertificate::PibCertificate()
: m_isValueSet(false)
{
}
PibCertificate::PibCertificate(const IdentityCertificate& certificate)
: m_isValueSet(true)
, m_certificate(certificate)
{
}
PibCertificate::PibCertificate(const Block& wire)
{
wireDecode(wire);
}
const IdentityCertificate&
PibCertificate::getCertificate() const
{
if (m_isValueSet)
return m_certificate;
else
throw tlv::Error("PibCertificate::getCertificate: certificate is not set");
}
template<bool T>
size_t
PibCertificate::wireEncode(EncodingImpl<T>& block) const
{
size_t totalLength = prependBlock(block, m_certificate.wireEncode());
totalLength += block.prependVarNumber(totalLength);
totalLength += block.prependVarNumber(tlv::pib::Certificate);
return totalLength;
}
template size_t
PibCertificate::wireEncode<true>(EncodingImpl<true>& block) const;
template size_t
PibCertificate::wireEncode<false>(EncodingImpl<false>& block) const;
const Block&
PibCertificate::wireEncode() const
{
if (m_wire.hasWire())
return m_wire;
EncodingEstimator estimator;
size_t estimatedSize = wireEncode(estimator);
EncodingBuffer buffer(estimatedSize, 0);
wireEncode(buffer);
m_wire = buffer.block();
return m_wire;
}
void
PibCertificate::wireDecode(const Block& wire)
{
if (!wire.hasWire()) {
throw tlv::Error("The supplied block does not contain wire format");
}
if (wire.type() != tlv::pib::Certificate)
throw tlv::Error("Unexpected TLV type when decoding PibCertificate");
m_wire = wire;
m_certificate.wireDecode(m_wire.blockFromValue());
m_isValueSet = true;
}
PibNameList::PibNameList()
{
}
PibNameList::PibNameList(const std::vector<Name>& names)
: m_names(names)
{
}
PibNameList::PibNameList(const Block& wire)
{
wireDecode(wire);
}
template<bool T>
size_t
PibNameList::wireEncode(EncodingImpl<T>& block) const
{
size_t totalLength = 0;
for (vector<Name>::const_reverse_iterator it = m_names.rbegin();
it != m_names.rend(); it++) {
totalLength += it->wireEncode(block);
}
totalLength += block.prependVarNumber(totalLength);
totalLength += block.prependVarNumber(tlv::pib::NameList);
return totalLength;
}
template size_t
PibNameList::wireEncode<true>(EncodingImpl<true>& block) const;
template size_t
PibNameList::wireEncode<false>(EncodingImpl<false>& block) const;
const Block&
PibNameList::wireEncode() const
{
if (m_wire.hasWire())
return m_wire;
EncodingEstimator estimator;
size_t estimatedSize = wireEncode(estimator);
EncodingBuffer buffer(estimatedSize, 0);
wireEncode(buffer);
m_wire = buffer.block();
return m_wire;
}
void
PibNameList::wireDecode(const Block& wire)
{
if (!wire.hasWire()) {
throw tlv::Error("The supplied block does not contain wire format");
}
if (wire.type() != tlv::pib::NameList)
throw tlv::Error("Unexpected TLV type when decoding PibNameList");
m_wire = wire;
m_wire.parse();
for (Block::element_const_iterator it = m_wire.elements_begin();
it != m_wire.elements_end(); it++) {
if (it->type() == tlv::Name) {
Name name;
name.wireDecode(*it);
m_names.push_back(name);
}
}
}
PibError::PibError()
: m_errCode(ERR_SUCCESS)
{
}
PibError::PibError(const pib::ErrCode errCode, const std::string& msg)
: m_errCode(errCode)
, m_msg(msg)
{
}
PibError::PibError(const Block& wire)
{
wireDecode(wire);
}
template<bool T>
size_t
PibError::wireEncode(EncodingImpl<T>& block) const
{
size_t totalLength = 0;
totalLength += prependByteArrayBlock(block, tlv::pib::Bytes,
reinterpret_cast<const uint8_t*>(m_msg.c_str()),
m_msg.size());
totalLength += prependNonNegativeIntegerBlock(block, tlv::pib::ErrorCode, m_errCode);
totalLength += block.prependVarNumber(totalLength);
totalLength += block.prependVarNumber(tlv::pib::Error);
return totalLength;
}
template size_t
PibError::wireEncode<true>(EncodingImpl<true>& block) const;
template size_t
PibError::wireEncode<false>(EncodingImpl<false>& block) const;
const Block&
PibError::wireEncode() const
{
if (m_wire.hasWire())
return m_wire;
EncodingEstimator estimator;
size_t estimatedSize = wireEncode(estimator);
EncodingBuffer buffer(estimatedSize, 0);
wireEncode(buffer);
m_wire = buffer.block();
return m_wire;
}
void
PibError::wireDecode(const Block& wire)
{
if (!wire.hasWire()) {
throw tlv::Error("The supplied block does not contain wire format");
}
if (wire.type() != tlv::pib::Error)
throw tlv::Error("Unexpected TLV type when decoding Error");
m_wire = wire;
m_wire.parse();
Block::element_const_iterator it = m_wire.elements_begin();
if (it != m_wire.elements_end() && it->type() == tlv::pib::ErrorCode) {
m_errCode = static_cast<pib::ErrCode>(readNonNegativeInteger(*it));
it++;
}
else
throw tlv::Error("PibError requires the first sub-TLV to be ErrorCode");
if (it != m_wire.elements_end() && it->type() == tlv::pib::Bytes) {
m_msg = string(reinterpret_cast<const char*>(it->value()), it->value_size());
it++;
}
else
throw tlv::Error("PibError requires the second sub-TLV to be Bytes");
}
PibUser::PibUser()
{
}
PibUser::PibUser(const Block& wire)
{
wireDecode(wire);
}
void
PibUser::setMgmtCert(const IdentityCertificate& mgmtCert)
{
m_wire.reset();
m_mgmtCert = mgmtCert;
}
void
PibUser::setTpmLocator(const std::string& tpmLocator)
{
m_wire.reset();
m_tpmLocator = tpmLocator;
}
template<bool T>
size_t
PibUser::wireEncode(EncodingImpl<T>& block) const
{
size_t totalLength = 0;
if (!m_tpmLocator.empty())
totalLength = prependByteArrayBlock(block, tlv::pib::TpmLocator,
reinterpret_cast<const uint8_t*>(m_tpmLocator.c_str()),
m_tpmLocator.size());
totalLength += prependBlock(block, m_mgmtCert.wireEncode());
totalLength += block.prependVarNumber(totalLength);
totalLength += block.prependVarNumber(tlv::pib::User);
return totalLength;
}
template size_t
PibUser::wireEncode<true>(EncodingImpl<true>& block) const;
template size_t
PibUser::wireEncode<false>(EncodingImpl<false>& block) const;
const Block&
PibUser::wireEncode() const
{
if (m_wire.hasWire())
return m_wire;
EncodingEstimator estimator;
size_t estimatedSize = wireEncode(estimator);
EncodingBuffer buffer(estimatedSize, 0);
wireEncode(buffer);
m_wire = buffer.block();
return m_wire;
}
void
PibUser::wireDecode(const Block& wire)
{
if (!wire.hasWire()) {
throw tlv::Error("The supplied block does not contain wire format");
}
if (wire.type() != tlv::pib::User)
throw tlv::Error("Unexpected TLV type when decoding Content");
m_wire = wire;
m_wire.parse();
Block::element_const_iterator it = m_wire.elements_begin();
if (it != m_wire.elements_end() && it->type() == tlv::Data) {
m_mgmtCert.wireDecode(*it);
it++;
}
else
throw tlv::Error("PibError requires the first sub-TLV to be Data");
if (it != m_wire.elements_end() && it->type() == tlv::pib::TpmLocator) {
m_tpmLocator = string(reinterpret_cast<const char*>(it->value()), it->value_size());
}
}
} // namespace pib
} // namespace ndn
+316
View File
@@ -0,0 +1,316 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#ifndef NDN_TOOLS_PIB_PIB_ENCODING_HPP
#define NDN_TOOLS_PIB_PIB_ENCODING_HPP
#include "pib-common.hpp"
#include <ndn-cxx/security/identity-certificate.hpp>
namespace ndn {
namespace pib {
/**
* @brief Abstraction of pib::Identity TLV.
*
* This class is copyable since it is used by a variety of pib parameters
*
* @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Query-Responses
*/
class PibIdentity
{
public:
PibIdentity();
explicit
PibIdentity(const Name& identity);
explicit
PibIdentity(const Block& wire);
const Name&
getIdentity() const
{
return m_identity;
}
template<bool T>
size_t
wireEncode(EncodingImpl<T>& block) const;
const Block&
wireEncode() const;
/**
* @brief Decode PibIdentity from a wire encoded block
*
* @throws tlv::Error if decoding fails
*/
void
wireDecode(const Block& wire);
private:
Name m_identity;
mutable Block m_wire;
};
/**
* @brief Abstraction of pib::PublicKey TLV.
*
* This class is copyable since it is used by a variety of pib parameters
*
* @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Query-Responses
*/
class PibPublicKey
{
public:
PibPublicKey();
PibPublicKey(const Name& keyName, const PublicKey& key);
explicit
PibPublicKey(const Block& wire);
const Name&
getKeyName() const;
const PublicKey&
getPublicKey() const;
template<bool T>
size_t
wireEncode(EncodingImpl<T>& block) const;
const Block&
wireEncode() const;
/**
* @brief Decode PibPublicKey from a wire encoded block
*
* @throws tlv::Error if decoding fails
*/
void
wireDecode(const Block& wire);
private:
bool m_isValueSet;
Name m_keyName;
PublicKey m_key;
mutable Block m_wire;
};
/**
* @brief Abstraction of pib::Certificate TLV.
*
* This class is copyable since it is used by a variety of pib parameters
*
* @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Query-Responses
*/
class PibCertificate
{
public:
PibCertificate();
explicit
PibCertificate(const IdentityCertificate& certificate);
explicit
PibCertificate(const Block& wire);
const IdentityCertificate&
getCertificate() const;
template<bool T>
size_t
wireEncode(EncodingImpl<T>& block) const;
const Block&
wireEncode() const;
/**
* @brief Decode PibCertificate from a wire encoded block
*
* @throws tlv::Error if decoding fails
*/
void
wireDecode(const Block& wire);
private:
bool m_isValueSet;
IdentityCertificate m_certificate;
mutable Block m_wire;
};
/**
* @brief Abstraction of pib::NameList TLV.
*
* @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#List-Parameters
*/
class PibNameList : noncopyable
{
public:
PibNameList();
explicit
PibNameList(const std::vector<Name>& names);
explicit
PibNameList(const Block& wire);
const std::vector<Name>&
getNameList() const
{
return m_names;
}
template<bool T>
size_t
wireEncode(EncodingImpl<T>& block) const;
const Block&
wireEncode() const;
/**
* @brief Decode PibCertificate from a wire encoded block
*
* @throws tlv::Error if decoding fails
*/
void
wireDecode(const Block& wire);
private:
std::vector<Name> m_names;
mutable Block m_wire;
};
/**
* @brief Abstraction of pib::Error TLV.
*
* @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Query-Responses
*/
class PibError : noncopyable
{
public:
PibError();
explicit
PibError(const pib::ErrCode errCode, const std::string& msg = "");
explicit
PibError(const Block& wire);
pib::ErrCode
getErrorCode() const
{
return m_errCode;
}
const std::string&
getErrorMsg() const
{
return m_msg;
}
template<bool T>
size_t
wireEncode(EncodingImpl<T>& block) const;
const Block&
wireEncode() const;
/**
* @brief Decode PibCertificate from a wire encoded block
*
* @throws tlv::Error if decoding fails
*/
void
wireDecode(const Block& wire);
private:
pib::ErrCode m_errCode;
std::string m_msg;
mutable Block m_wire;
};
/**
* @brief Abstraction of pib::User TLV.
*
* This class is copyable since it is used by a variety of pib parameters
*
* @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Query-Responses
*/
class PibUser
{
public:
PibUser();
explicit
PibUser(const Block& wire);
void
setMgmtCert(const IdentityCertificate& mgmtCert);
const IdentityCertificate&
getMgmtCert() const
{
return m_mgmtCert;
}
void
setTpmLocator(const std::string& tpmLocator);
const std::string&
getTpmLocator() const
{
return m_tpmLocator;
}
template<bool T>
size_t
wireEncode(EncodingImpl<T>& block) const;
const Block&
wireEncode() const;
/**
* @brief Decode PibCertificate from a wire encoded block
*
* @throws tlv::Error if decoding fails
*/
void
wireDecode(const Block& wire);
private:
IdentityCertificate m_mgmtCert;
std::string m_tpmLocator;
mutable Block m_wire;
};
} // namespace pib
} // namespace ndn
#endif // NDN_TOOLS_PIB_PIB_ENCODING_HPP
+235
View File
@@ -0,0 +1,235 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "update-param.hpp"
#include <ndn-cxx/encoding/block-helpers.hpp>
#include <boost/lexical_cast.hpp>
namespace ndn {
namespace pib {
static_assert(std::is_base_of<tlv::Error, UpdateParam::Error>::value,
"UpdateParam::Error must inherit from tlv::Error");
const std::string UpdateParam::VERB("update");
UpdateParam::UpdateParam()
: m_defaultOpt(DEFAULT_OPT_NO)
{
}
UpdateParam::UpdateParam(const PibUser& user)
: m_entityType(tlv::pib::User)
, m_user(user)
, m_defaultOpt(DEFAULT_OPT_NO)
{
}
UpdateParam::UpdateParam(const Name& identity, DefaultOpt defaultOpt)
: m_entityType(tlv::pib::Identity)
, m_identity(identity)
, m_defaultOpt(defaultOpt)
{
}
UpdateParam::UpdateParam(const Name& keyName, const PublicKey& key, DefaultOpt defaultOpt)
: m_entityType(tlv::pib::PublicKey)
, m_key(keyName, key)
, m_defaultOpt(defaultOpt)
{
}
UpdateParam::UpdateParam(const IdentityCertificate& certificate, DefaultOpt defaultOpt)
: m_entityType(tlv::pib::Certificate)
, m_certificate(certificate)
, m_defaultOpt(defaultOpt)
{
}
UpdateParam::UpdateParam(const Block& wire)
{
wireDecode(wire);
}
const PibUser&
UpdateParam::getUser() const
{
if (m_entityType == tlv::pib::User)
return m_user;
else
throw Error("UpdateParam::getUser: entityType must be User");
}
const PibIdentity&
UpdateParam::getIdentity() const
{
if (m_entityType == tlv::pib::Identity)
return m_identity;
else
throw Error("UpdateParam::getIdentity: entityType must be Identity");
}
const PibPublicKey&
UpdateParam::getPublicKey() const
{
if (m_entityType == tlv::pib::PublicKey)
return m_key;
else
throw Error("UpdateParam::getPublicKey: entityType must be PublicKey");
}
const PibCertificate&
UpdateParam::getCertificate() const
{
if (m_entityType == tlv::pib::Certificate)
return m_certificate;
else
throw Error("UpdateParam::getCertificate: entityType must be Certificate");
}
template<bool T>
size_t
UpdateParam::wireEncode(EncodingImpl<T>& block) const
{
size_t totalLength = 0;
totalLength += prependNonNegativeIntegerBlock(block, tlv::pib::DefaultOpt, m_defaultOpt);
// Encode Entity
switch (m_entityType) {
case tlv::pib::Identity:
{
totalLength += m_identity.wireEncode(block);
break;
}
case tlv::pib::PublicKey:
{
totalLength += m_key.wireEncode(block);
break;
}
case tlv::pib::Certificate:
{
totalLength += m_certificate.wireEncode(block);
break;
}
case tlv::pib::User:
{
totalLength += m_user.wireEncode(block);
break;
}
default:
throw Error("UpdateParam::wireEncode: unsupported entity type: " +
boost::lexical_cast<std::string>(m_entityType));
}
totalLength += block.prependVarNumber(totalLength);
totalLength += block.prependVarNumber(tlv::pib::UpdateParam);
return totalLength;
}
template size_t
UpdateParam::wireEncode<true>(EncodingImpl<true>& block) const;
template size_t
UpdateParam::wireEncode<false>(EncodingImpl<false>& block) const;
const Block&
UpdateParam::wireEncode() const
{
if (m_wire.hasWire())
return m_wire;
EncodingEstimator estimator;
size_t estimatedSize = wireEncode(estimator);
EncodingBuffer buffer(estimatedSize, 0);
wireEncode(buffer);
m_wire = buffer.block();
return m_wire;
}
void
UpdateParam::wireDecode(const Block& wire)
{
if (!wire.hasWire()) {
throw Error("The supplied block does not contain wire format");
}
m_wire = wire;
m_wire.parse();
if (m_wire.type() != tlv::pib::UpdateParam)
throw Error("Unexpected TLV type when decoding UpdateParam");
Block::element_const_iterator it = m_wire.elements_begin();
// the first block must be Entity
if (it != m_wire.elements_end()) {
switch (it->type()) {
case tlv::pib::Identity:
{
m_entityType = tlv::pib::Identity;
m_identity.wireDecode(*it);
break;
}
case tlv::pib::PublicKey:
{
m_entityType = tlv::pib::PublicKey;
m_key.wireDecode(*it);
break;
}
case tlv::pib::Certificate:
{
m_entityType = tlv::pib::Certificate;
m_certificate.wireDecode(*it);
break;
}
case tlv::pib::User:
{
m_entityType = tlv::pib::User;
m_user.wireDecode(*it);
break;
}
default:
throw Error("The first sub-TLV of UpdateParam is not an entity type");
}
it++;
}
else
throw Error("UpdateParam requires the first sub-TLV to be an entity type");
// the second block must be DefaultOpt
if (it != m_wire.elements_end() && it->type() == tlv::pib::DefaultOpt) {
m_defaultOpt = static_cast<pib::DefaultOpt>(readNonNegativeInteger(*it));
it++;
}
else
throw Error("UpdateParam requires the second sub-TLV to be DefaultOpt");
if (it != m_wire.elements_end())
throw Error("UpdateParam must not contain more than two sub-TLVs");
}
} // namespace pib
} // namespace ndn
+136
View File
@@ -0,0 +1,136 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#ifndef NDN_TOOLS_PIB_UPDATE_PARAM_HPP
#define NDN_TOOLS_PIB_UPDATE_PARAM_HPP
#include "pib-common.hpp"
#include "pib-encoding.hpp"
#include <ndn-cxx/name.hpp>
#include <ndn-cxx/security/identity-certificate.hpp>
namespace ndn {
namespace pib {
/**
* @brief UpdateParam is the abstraction of PIB Update parameter.
*
* PibUpdateParam := PIB-UPDATE-PARAM-TYPE TLV-LENGTH
* (PibIdentity | PibPublicKey | PibCertificate)
* PibDefaultOpt
*
* @sa http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base#Update-Parameters
*/
class UpdateParam : noncopyable
{
public:
class Error : public tlv::Error
{
public:
explicit
Error(const std::string& what)
: tlv::Error(what)
{
}
};
UpdateParam();
explicit
UpdateParam(const PibUser& user);
explicit
UpdateParam(const Name& identity, DefaultOpt defaultOpt = DEFAULT_OPT_NO);
UpdateParam(const Name& keyName, const PublicKey& key, DefaultOpt defaultOpt = DEFAULT_OPT_NO);
explicit
UpdateParam(const IdentityCertificate& certificate, DefaultOpt defaultOpt = DEFAULT_OPT_NO);
explicit
UpdateParam(const Block& wire);
tlv::pib::ParamType
getParamType() const
{
return tlv::pib::UpdateParam;
}
tlv::pib::EntityType
getEntityType() const
{
return m_entityType;
}
const PibUser&
getUser() const;
const PibIdentity&
getIdentity() const;
const PibPublicKey&
getPublicKey() const;
const PibCertificate&
getCertificate() const;
pib::DefaultOpt
getDefaultOpt() const
{
return m_defaultOpt;
}
/// @brief Encode to a wire format or estimate wire format
template<bool T>
size_t
wireEncode(EncodingImpl<T>& block) const;
/// @brief Encode to a wire format
const Block&
wireEncode() const;
/**
* @brief Decode GetParam from a wire encoded block
*
* @throws Error if decoding fails
*/
void
wireDecode(const Block& wire);
public:
static const std::string VERB;
private:
tlv::pib::EntityType m_entityType;
PibUser m_user;
PibIdentity m_identity;
PibPublicKey m_key;
PibCertificate m_certificate;
pib::DefaultOpt m_defaultOpt;
mutable Block m_wire;
};
} // namespace pib
} // namespace ndn
#endif // NDN_TOOLS_PIB_UPDATE_PARAM_HPP
+132
View File
@@ -0,0 +1,132 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "get-query-processor.hpp"
#include "encoding/pib-encoding.hpp"
#include <boost/lexical_cast.hpp>
namespace ndn {
namespace pib {
const Name GetQueryProcessor::PIB_PREFIX("/localhost/pib");
const size_t GetQueryProcessor::GET_QUERY_LENGTH = 5;
GetQueryProcessor::GetQueryProcessor(PibDb& db)
: m_db(db)
{
}
std::pair<bool, Block>
GetQueryProcessor::operator()(const Interest& interest)
{
const Name& interestName = interest.getName();
// handle pib query: /localhost/pib/[UserName]/get/param
if (interestName.size() != GET_QUERY_LENGTH) {
// malformed interest, discard
return std::make_pair(false, Block());
}
GetParam param;
try {
param.wireDecode(interestName.get(OFFSET_PARAM).blockFromValue());
}
catch (const tlv::Error& e) {
PibError error(ERR_WRONG_PARAM, "error in parsing param: " + std::string(e.what()));
return std::make_pair(true, error.wireEncode());
}
switch (param.getTargetType()) {
case TYPE_ID:
return processGetIdQuery(param);
case TYPE_KEY:
return processGetKeyQuery(param);
case TYPE_CERT:
return processGetCertQuery(param);
case TYPE_USER:
if (interest.getName().get(2).toUri() != m_db.getOwnerName())
return std::make_pair(false, Block());
else
return processGetUserQuery(param);
default:
{
PibError error(ERR_WRONG_PARAM, "requested type is not supported:" +
boost::lexical_cast<std::string>(param.getTargetType()));
return std::make_pair(true, error.wireEncode());
}
}
}
std::pair<bool, Block>
GetQueryProcessor::processGetIdQuery(const GetParam& param)
{
if (!m_db.hasIdentity(param.getTargetName())) {
PibError error(ERR_NON_EXISTING_ID, "requested id does not exist");
return std::make_pair(true, error.wireEncode());
}
PibIdentity result(param.getTargetName());
return std::make_pair(true, result.wireEncode());
}
std::pair<bool, Block>
GetQueryProcessor::processGetKeyQuery(const GetParam& param)
{
if (param.getTargetName().empty()) {
PibError error(ERR_WRONG_PARAM, "key name does not have id-component");
return std::make_pair(true, error.wireEncode());
}
shared_ptr<PublicKey> key = m_db.getKey(param.getTargetName());
if (key == nullptr) {
PibError error(ERR_NON_EXISTING_KEY, "requested key does not exist");
return std::make_pair(true, error.wireEncode());
}
PibPublicKey result(param.getTargetName(), *key);
return std::make_pair(true, result.wireEncode());
}
std::pair<bool, Block>
GetQueryProcessor::processGetCertQuery(const GetParam& param)
{
shared_ptr<IdentityCertificate> certificate = m_db.getCertificate(param.getTargetName());
if (certificate == nullptr) {
PibError error(ERR_NON_EXISTING_CERT, "requested certificate does not exist");
return std::make_pair(true, error.wireEncode());
}
PibCertificate result(*certificate);
return std::make_pair(true, result.wireEncode());
}
std::pair<bool, Block>
GetQueryProcessor::processGetUserQuery(const GetParam& param)
{
PibUser result;
result.setMgmtCert(*m_db.getMgmtCertificate());
result.setTpmLocator(m_db.getTpmLocator());
return std::make_pair(true, result.wireEncode());
}
} // namespace pib
} // namespace ndn
+82
View File
@@ -0,0 +1,82 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#ifndef NDN_TOOLS_PIB_GET_QUERY_PROCESSOR_HPP
#define NDN_TOOLS_PIB_GET_QUERY_PROCESSOR_HPP
#include "pib-db.hpp"
#include "encoding/get-param.hpp"
#include <ndn-cxx/interest.hpp>
#include <utility>
namespace ndn {
namespace pib {
/// @brief implements the PIB service
class GetQueryProcessor : noncopyable
{
public:
class Error : public std::runtime_error
{
public:
explicit
Error(const std::string& what)
: std::runtime_error(what)
{
}
};
/**
* @brief Constructor
*
* @param db The pib database.
* @param owner Owner of the pib database.
*/
explicit
GetQueryProcessor(PibDb& db);
std::pair<bool, Block>
operator()(const Interest& interest);
private:
std::pair<bool, Block>
processGetUserQuery(const GetParam& param);
std::pair<bool, Block>
processGetIdQuery(const GetParam& param);
std::pair<bool, Block>
processGetKeyQuery(const GetParam& param);
std::pair<bool, Block>
processGetCertQuery(const GetParam& param);
private:
static const Name PIB_PREFIX;
static const size_t GET_QUERY_LENGTH;
const PibDb& m_db;
};
} // namespace pib
} // namespace ndn
#endif // NDN_TOOLS_PIB_GET_QUERY_PROCESSOR_HPP
+106
View File
@@ -0,0 +1,106 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "key-cache.hpp"
namespace ndn {
namespace pib {
KeyCacheEntry::KeyCacheEntry(const Name& name, shared_ptr<PublicKey> key)
: name(name)
, key(key)
{
BOOST_ASSERT(static_cast<bool>(key));
}
KeyCache::KeyCache(size_t capacity)
: m_capacity(capacity)
{
}
void
KeyCache::insert(const Name& name, shared_ptr<PublicKey> key)
{
// check if key exist
KeyContainer::index<byName>::type::iterator it = m_keys.get<byName>().find(name);
if (it != m_keys.get<byName>().end()) {
adjustLru(it);
return;
}
// evict key when capacity is reached
if (size() >= m_capacity)
evictKey();
// insert entry
m_keys.insert(KeyCacheEntry(name, key));
}
shared_ptr<PublicKey>
KeyCache::find(const Name& name) const
{
// check if key exist
KeyContainer::index<byName>::type::iterator it = m_keys.get<byName>().find(name);
if (it == m_keys.get<byName>().end())
return shared_ptr<PublicKey>();
else {
// adjust lru
shared_ptr<PublicKey> key = it->key;
adjustLru(it);
return key;
}
}
void
KeyCache::erase(const Name& name)
{
// check if key exist
KeyContainer::index<byName>::type::iterator it = m_keys.get<byName>().find(name);
if (it != m_keys.get<byName>().end()) {
m_keys.erase(it);
}
}
size_t
KeyCache::size() const
{
return m_keys.size();
}
void
KeyCache::evictKey()
{
if (!m_keys.get<byUsedTime>().empty()) {
KeyContainer::index<byUsedTime>::type::iterator it = m_keys.get<byUsedTime>().begin();
m_keys.erase(m_keys.project<0>(it));
}
}
void
KeyCache::adjustLru(KeyContainer::iterator it) const
{
KeyCacheEntry entry = std::move(*it);
m_keys.erase(it);
m_keys.insert(entry);
}
} // namespace pib
} // namespace ndn
+108
View File
@@ -0,0 +1,108 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#ifndef NDN_TOOLS_PIB_KEY_CACHE_HPP
#define NDN_TOOLS_PIB_KEY_CACHE_HPP
#include <ndn-cxx/name.hpp>
#include <ndn-cxx/util/time.hpp>
#include <ndn-cxx/security/public-key.hpp>
#include <stack>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/key_extractors.hpp>
namespace ndn {
namespace pib {
struct KeyCacheEntry
{
KeyCacheEntry(const Name& name, shared_ptr<PublicKey> key);
Name name;
shared_ptr<PublicKey> key;
};
class byName;
class byUsedTime;
typedef boost::multi_index::multi_index_container<
KeyCacheEntry,
boost::multi_index::indexed_by<
boost::multi_index::hashed_unique<
boost::multi_index::tag<byName>,
boost::multi_index::member<KeyCacheEntry, Name, &KeyCacheEntry::name>,
std::hash<Name>
>,
boost::multi_index::sequenced<
boost::multi_index::tag<byUsedTime>
>
>
> KeyContainer;
class KeyCache : noncopyable
{
public:
explicit
KeyCache(size_t capacity = getDefaultCapacity());
void
insert(const Name& name, shared_ptr<PublicKey> key);
shared_ptr<PublicKey>
find(const Name& name) const;
void
erase(const Name& name);
size_t
size() const;
private:
static size_t
getDefaultCapacity()
{
return 100;
}
void
evictKey();
void
adjustLru(KeyContainer::iterator it) const;
void
freeEntry(KeyContainer::iterator it);
private:
size_t m_capacity;
mutable KeyContainer m_keys;
};
} // namespace pib
} // namespace ndn
#endif // NDN_TOOLS_PIB_KEY_CACHE_HPP
+98
View File
@@ -0,0 +1,98 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "list-query-processor.hpp"
#include "encoding/pib-encoding.hpp"
#include <boost/lexical_cast.hpp>
namespace ndn {
namespace pib {
using std::string;
using std::vector;
const size_t ListQueryProcessor::LIST_QUERY_LENGTH = 5;
ListQueryProcessor::ListQueryProcessor(PibDb& db)
: m_db(db)
{
}
std::pair<bool, Block>
ListQueryProcessor::operator()(const Interest& interest)
{
const Name& interestName = interest.getName();
// handle pib query: /localhost/pib/[UserName]/list/param
if (interestName.size() != MIN_PIB_INTEREST_SIZE) {
// malformed interest, discard
return std::make_pair(false, Block());
}
ListParam param;
try {
param.wireDecode(interestName.get(OFFSET_PARAM).blockFromValue());
}
catch (const tlv::Error& e) {
PibError error(ERR_WRONG_PARAM, "error in parsing param: " + string(e.what()));
return std::make_pair(true, error.wireEncode());
}
vector<Name> nameList;
switch (param.getOriginType()) {
case TYPE_USER:
{
nameList = m_db.listIdentities();
break;
}
case TYPE_ID:
{
nameList = m_db.listKeyNamesOfIdentity(param.getOriginName());
break;
}
case TYPE_KEY:
{
const Name& keyName = param.getOriginName();
if (keyName.empty()) {
PibError error(ERR_WRONG_PARAM,
"key name must contain key id component");
return std::make_pair(true, error.wireEncode());
}
nameList = m_db.listCertNamesOfKey(keyName);
break;
}
default:
{
PibError error(ERR_WRONG_PARAM,
"origin type is not supported: " +
boost::lexical_cast<string>(param.getOriginType()));
return std::make_pair(true, error.wireEncode());
}
}
PibNameList result(nameList);
return std::make_pair(true, result.wireEncode());
}
} // namespace pib
} // namespace ndn
+66
View File
@@ -0,0 +1,66 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#ifndef NDN_TOOLS_PIB_LIST_QUERY_PROCESSOR_HPP
#define NDN_TOOLS_PIB_LIST_QUERY_PROCESSOR_HPP
#include "pib-db.hpp"
#include "encoding/list-param.hpp"
#include <ndn-cxx/interest.hpp>
#include <utility>
namespace ndn {
namespace pib {
class ListQueryProcessor : noncopyable
{
public:
class Error : public std::runtime_error
{
public:
explicit
Error(const std::string& what)
: std::runtime_error(what)
{
}
};
/**
* @brief Constructor
*
* @param db The pib database.
*/
explicit
ListQueryProcessor(PibDb& db);
std::pair<bool, Block>
operator()(const Interest& interest);
private:
static const size_t LIST_QUERY_LENGTH;
const PibDb& m_db;
};
} // namespace pib
} // namespace ndn
#endif // NDN_TOOLS_PIB_LIST_QUERY_PROCESSOR_HPP
+127
View File
@@ -0,0 +1,127 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "pib.hpp"
#include <ndn-cxx/util/io.hpp>
#include <ndn-cxx/util/config-file.hpp>
#include <ndn-cxx/security/key-chain.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/filesystem.hpp>
namespace ndn {
namespace pib {
int
main(int argc, char** argv)
{
namespace po = boost::program_options;
namespace fs = boost::filesystem;
std::string owner;
std::string dbDir;
std::string tpmLocator;
Face face;
std::cerr << "hello" << std::endl;
po::options_description description(
"General Usage\n"
" ndn-pib [-h] -o owner -d database_dir -t tpm_locator\n"
"General options");
description.add_options()
("help,h", "produce help message")
("owner,o", po::value<std::string>(&owner),
"Name of the owner, PIB will listen to /localhost/pib/[owner].")
("database,d", po::value<std::string>(&dbDir),
"Absolute path to the directory of PIB database, /<database_dir>/pib.db")
("tpm,t", po::value<std::string>(&tpmLocator),
"URI of the tpm. e.g., tpm-file:/var")
;
po::variables_map vm;
try {
po::store(po::parse_command_line(argc, argv, description), vm);
po::notify(vm);
}
catch (const std::exception& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
std::cerr << description << std::endl;
return 1;
}
if (vm.count("help") != 0) {
std::cerr << description << std::endl;
return 0;
}
try {
if (vm.count("owner") == 0 && vm.count("database") == 0 && vm.count("tpm") == 0) {
if (std::getenv("HOME")) {
fs::path pibDir(std::getenv("HOME"));
pibDir /= ".ndn/pib";
dbDir = pibDir.string();
}
else {
std::cerr << "ERROR: HOME variable is not set" << std::endl;
return 1;
}
tpmLocator = KeyChain::getDefaultTpmLocator();
if (std::getenv("USER")) {
owner = std::string(std::getenv("USER"));
}
else {
std::cerr << "ERROR: HOME variable is not set" << std::endl;
return 1;
}
}
else if (vm.count("owner") == 0 || vm.count("database") == 0 ||
vm.count("tpm") == 0) {
std::cerr << description << std::endl;
return 1;
}
Pib pib(face, dbDir, tpmLocator, owner);
face.processEvents();
}
catch (std::runtime_error& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
return 1;
}
return 0;
}
} // namespace pib
} // namespace ndn
int
main(int argc, char** argv)
{
return ndn::pib::main(argc, argv);
}
+825
View File
@@ -0,0 +1,825 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "pib-db.hpp"
#include <sqlite3.h>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
namespace ndn {
namespace pib {
using std::string;
using std::vector;
using std::set;
const Name PibDb::NON_EXISTING_IDENTITY("/localhost/reserved/non-existing-identity");
const Name PibDb::NON_EXISTING_KEY("/localhost/reserved/non-existing-key");
const Name PibDb::NON_EXISTING_CERTIFICATE("/localhost/reserved/non-existing-certificate");
const Name PibDb::LOCALHOST_PIB("/localhost/pib");
const name::Component PibDb::MGMT_LABEL("mgmt");
static const string INITIALIZATION =
"CREATE TABLE IF NOT EXISTS \n"
" mgmt( \n"
" id INTEGER PRIMARY KEY,\n"
" owner BLOB NOT NULL, \n"
" tpm_locator BLOB, \n"
" local_management_cert BLOB NOT NULL \n"
" ); \n"
"CREATE TRIGGER IF NOT EXISTS \n"
" mgmt_insert_trigger \n"
" BEFORE INSERT ON mgmt \n"
" FOR EACH ROW \n"
" BEGIN \n"
" DELETE FROM mgmt; \n"
" END; \n"
" \n"
"CREATE TABLE IF NOT EXISTS \n"
" identities( \n"
" id INTEGER PRIMARY KEY,\n"
" identity BLOB NOT NULL, \n"
" is_default INTEGER DEFAULT 0 \n"
" ); \n"
"CREATE UNIQUE INDEX IF NOT EXISTS \n"
" identityIndex ON identities(identity); \n"
"CREATE TRIGGER IF NOT EXISTS \n"
" identity_default_before_insert_trigger \n"
" BEFORE INSERT ON identities \n"
" FOR EACH ROW \n"
" WHEN NEW.is_default=1 \n"
" BEGIN \n"
" UPDATE identities SET is_default=0; \n"
" END; \n"
"CREATE TRIGGER IF NOT EXISTS \n"
" identity_default_after_insert_trigger \n"
" AFTER INSERT ON identities \n"
" FOR EACH ROW \n"
" WHEN NOT EXISTS \n"
" (SELECT id \n"
" FROM identities \n"
" WHERE is_default=1) \n"
" BEGIN \n"
" UPDATE identities \n"
" SET is_default=1 \n"
" WHERE identity=NEW.identity; \n"
" END; \n"
"CREATE TRIGGER IF NOT EXISTS \n"
" identity_default_update_trigger \n"
" BEFORE UPDATE ON identities \n"
" FOR EACH ROW \n"
" WHEN NEW.is_default=1 AND OLD.is_default=0 \n"
" BEGIN \n"
" UPDATE identities SET is_default=0; \n"
" END; \n"
"CREATE TRIGGER IF NOT EXISTS \n"
" identity_delete_trigger \n"
" AFTER DELETE ON identities \n"
" FOR EACH ROW \n"
" BEGIN \n"
" SELECT identityDeleted (OLD.identity); \n"
" END; \n"
" \n"
"CREATE TABLE IF NOT EXISTS \n"
" keys( \n"
" id INTEGER PRIMARY KEY,\n"
" identity_id INTEGER NOT NULL, \n"
" key_name BLOB NOT NULL, \n"
" key_type INTEGER NOT NULL, \n"
" key_bits BLOB NOT NULL, \n"
" is_default INTEGER DEFAULT 0, \n"
" FOREIGN KEY(identity_id) \n"
" REFERENCES identities(id) \n"
" ON DELETE CASCADE \n"
" ON UPDATE CASCADE \n"
" ); \n"
"CREATE UNIQUE INDEX IF NOT EXISTS \n"
" keyIndex ON keys(key_name); \n"
"CREATE TRIGGER IF NOT EXISTS \n"
" key_default_before_insert_trigger \n"
" BEFORE INSERT ON keys \n"
" FOR EACH ROW \n"
" WHEN NEW.is_default=1 \n"
" BEGIN \n"
" UPDATE keys \n"
" SET is_default=0 \n"
" WHERE identity_id=NEW.identity_id; \n"
" END; \n"
"CREATE TRIGGER IF NOT EXISTS \n"
" key_default_after_insert_trigger \n"
" AFTER INSERT ON keys \n"
" FOR EACH ROW \n"
" WHEN NOT EXISTS \n"
" (SELECT id \n"
" FROM keys \n"
" WHERE is_default=1 \n"
" AND identity_id=NEW.identity_id) \n"
" BEGIN \n"
" UPDATE keys \n"
" SET is_default=1 \n"
" WHERE key_name=NEW.key_name; \n"
" END; \n"
"CREATE TRIGGER IF NOT EXISTS \n"
" key_default_update_trigger \n"
" BEFORE UPDATE ON keys \n"
" FOR EACH ROW \n"
" WHEN NEW.is_default=1 AND OLD.is_default=0 \n"
" BEGIN \n"
" UPDATE keys \n"
" SET is_default=0 \n"
" WHERE identity_id=NEW.identity_id; \n"
" END; \n"
"CREATE TRIGGER IF NOT EXISTS \n"
" key_delete_trigger \n"
" AFTER DELETE ON keys \n"
" FOR EACH ROW \n"
" BEGIN \n"
" SELECT keyDeleted (OLD.key_name); \n"
" END; \n"
" \n"
"CREATE TABLE IF NOT EXISTS \n"
" certificates( \n"
" id INTEGER PRIMARY KEY,\n"
" key_id INTEGER NOT NULL, \n"
" certificate_name BLOB NOT NULL, \n"
" certificate_data BLOB NOT NULL, \n"
" is_default INTEGER DEFAULT 0, \n"
" FOREIGN KEY(key_id) \n"
" REFERENCES keys(id) \n"
" ON DELETE CASCADE \n"
" ON UPDATE CASCADE \n"
" ); \n"
"CREATE UNIQUE INDEX IF NOT EXISTS \n"
" certIndex ON certificates(certificate_name);\n"
"CREATE TRIGGER IF NOT EXISTS \n"
" cert_default_before_insert_trigger \n"
" BEFORE INSERT ON certificates \n"
" FOR EACH ROW \n"
" WHEN NEW.is_default=1 \n"
" BEGIN \n"
" UPDATE certificates \n"
" SET is_default=0 \n"
" WHERE key_id=NEW.key_id; \n"
" END; \n"
"CREATE TRIGGER IF NOT EXISTS \n"
" cert_default_after_insert_trigger \n"
" AFTER INSERT ON certificates \n"
" FOR EACH ROW \n"
" WHEN NOT EXISTS \n"
" (SELECT id \n"
" FROM certificates \n"
" WHERE is_default=1 \n"
" AND key_id=NEW.key_id) \n"
" BEGIN \n"
" UPDATE certificates \n"
" SET is_default=1 \n"
" WHERE certificate_name=NEW.certificate_name;\n"
" END; \n"
"CREATE TRIGGER IF NOT EXISTS \n"
" cert_default_update_trigger \n"
" BEFORE UPDATE ON certificates \n"
" FOR EACH ROW \n"
" WHEN NEW.is_default=1 AND OLD.is_default=0 \n"
" BEGIN \n"
" UPDATE certificates \n"
" SET is_default=0 \n"
" WHERE key_id=NEW.key_id; \n"
" END; \n"
"CREATE TRIGGER IF NOT EXISTS \n"
" cert_delete_trigger \n"
" AFTER DELETE ON certificates \n"
" FOR EACH ROW \n"
" BEGIN \n"
" SELECT certDeleted (OLD.certificate_name);\n"
" END; \n"
"CREATE TRIGGER IF NOT EXISTS \n"
" cert_insert_trigger \n"
" AFTER INSERT ON certificates \n"
" FOR EACH ROW \n"
" BEGIN \n"
" SELECT certInserted (NEW.certificate_name);\n"
" END; \n";
/**
* A utility function to call the normal sqlite3_bind_text where the value and length are
* value.c_str() and value.size().
*/
static int
sqlite3_bind_string(sqlite3_stmt* statement,
int index,
const string& value,
void(*destructor)(void*))
{
return sqlite3_bind_text(statement, index, value.c_str(), value.size(), destructor);
}
/**
* A utility function to call the normal sqlite3_bind_blob where the value and length are
* block.wire() and block.size().
*/
static int
sqlite3_bind_block(sqlite3_stmt* statement,
int index,
const Block& block,
void(*destructor)(void*))
{
return sqlite3_bind_blob(statement, index, block.wire(), block.size(), destructor);
}
/**
* A utility function to generate string by calling the normal sqlite3_column_text.
*/
static string
sqlite3_column_string(sqlite3_stmt* statement, int column)
{
return string(reinterpret_cast<const char*>(sqlite3_column_text(statement, column)),
sqlite3_column_bytes(statement, column));
}
/**
* A utility function to generate block by calling the normal sqlite3_column_text.
*/
static Block
sqlite3_column_block(sqlite3_stmt* statement, int column)
{
return Block(sqlite3_column_blob(statement, column), sqlite3_column_bytes(statement, column));
}
PibDb::PibDb(const string& dbDir)
{
// Determine the path of PIB DB
boost::filesystem::path dir;
if (dbDir == "") {
dir = boost::filesystem::path(getenv("HOME")) / ".ndn";
boost::filesystem::create_directories(dir);
}
else {
dir = boost::filesystem::path(dbDir);
boost::filesystem::create_directories(dir);
}
// Open PIB
int result = sqlite3_open_v2((dir / "pib.db").c_str(), &m_database,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
#ifdef NDN_CXX_DISABLE_SQLITE3_FS_LOCKING
"unix-dotfile"
#else
nullptr
#endif
);
if (result != SQLITE_OK)
throw Error("PIB DB cannot be opened/created: " + dbDir);
// enable foreign key
sqlite3_exec(m_database, "PRAGMA foreign_keys = ON", nullptr, nullptr, nullptr);
// initialize PIB specific tables
char* errorMessage = nullptr;
result = sqlite3_exec(m_database, INITIALIZATION.c_str(), nullptr, nullptr, &errorMessage);
if (result != SQLITE_OK && errorMessage != nullptr) {
sqlite3_free(errorMessage);
throw Error("PIB DB cannot be initialized");
}
// create delete trigger functions
createDbDeleteTrigger();
getOwnerName();
}
void
PibDb::createDbDeleteTrigger()
{
int res = 0;
res = sqlite3_create_function(m_database, "identityDeleted", -1, SQLITE_UTF8,
reinterpret_cast<void*>(this),
PibDb::identityDeletedFun, nullptr, nullptr);
if (res != SQLITE_OK)
throw Error("Cannot create function ``identityDeleted''");
res = sqlite3_create_function(m_database, "keyDeleted", -1, SQLITE_UTF8,
reinterpret_cast<void*>(this),
PibDb::keyDeletedFun, nullptr, nullptr);
if (res != SQLITE_OK)
throw Error("Cannot create function ``keyDeleted''");
res = sqlite3_create_function(m_database, "certDeleted", -1, SQLITE_UTF8,
reinterpret_cast<void*>(this),
PibDb::certDeletedFun, nullptr, nullptr);
if (res != SQLITE_OK)
throw Error("Cannot create function ``certDeleted''");
res = sqlite3_create_function(m_database, "certInserted", -1, SQLITE_UTF8,
reinterpret_cast<void*>(this),
PibDb::certInsertedFun, nullptr, nullptr);
if (res != SQLITE_OK)
throw Error("Cannot create function ``certInserted''");
}
void
PibDb::identityDeletedFun(sqlite3_context* context, int argc, sqlite3_value** argv)
{
BOOST_ASSERT(argc == 1);
PibDb* pibDb = reinterpret_cast<PibDb*>(sqlite3_user_data(context));
Name identity(Block(sqlite3_value_blob(argv[0]), sqlite3_value_bytes(argv[0])));
pibDb->identityDeleted(identity);
}
void
PibDb::keyDeletedFun(sqlite3_context* context, int argc, sqlite3_value** argv)
{
BOOST_ASSERT(argc == 1);
PibDb* pibDb = reinterpret_cast<PibDb*>(sqlite3_user_data(context));
Name keyName(Block(sqlite3_value_blob(argv[0]), sqlite3_value_bytes(argv[0])));
pibDb->keyDeleted(keyName);
}
void
PibDb::certDeletedFun(sqlite3_context* context, int argc, sqlite3_value** argv)
{
BOOST_ASSERT(argc == 1);
PibDb* pibDb = reinterpret_cast<PibDb*>(sqlite3_user_data(context));
Name certName(Block(sqlite3_value_blob(argv[0]), sqlite3_value_bytes(argv[0])));
pibDb->certificateDeleted(certName);
}
void
PibDb::certInsertedFun(sqlite3_context* context, int argc, sqlite3_value** argv)
{
BOOST_ASSERT(argc == 1);
PibDb* pibDb = reinterpret_cast<PibDb*>(sqlite3_user_data(context));
Name certName(Block(sqlite3_value_blob(argv[0]), sqlite3_value_bytes(argv[0])));
pibDb->certificateInserted(certName);
}
void
PibDb::updateMgmtCertificate(const IdentityCertificate& certificate)
{
const Name& keyName = certificate.getPublicKeyName();
// Name of mgmt key should be "/localhost/pib/[UserName]/mgmt/[KeyID]"
if (keyName.size() != 5 ||
keyName.compare(0, 2, LOCALHOST_PIB) ||
keyName.get(3) != MGMT_LABEL)
throw Error("PibDb::updateMgmtCertificate: certificate does not follow the naming convention");
string owner = keyName.get(2).toUri();
sqlite3_stmt* statement;
if (!m_owner.empty()) {
if (m_owner != owner)
throw Error("PibDb::updateMgmtCertificate: owner name does not match");
else {
sqlite3_prepare_v2(m_database,
"UPDATE mgmt SET local_management_cert=? WHERE owner=?",
-1, &statement, nullptr);
}
}
else {
sqlite3_prepare_v2(m_database,
"INSERT INTO mgmt (local_management_cert, owner) VALUES (?, ?)",
-1, &statement, nullptr);
}
sqlite3_bind_block(statement, 1, certificate.wireEncode(), SQLITE_TRANSIENT);
sqlite3_bind_string(statement, 2, owner, SQLITE_TRANSIENT);
sqlite3_step(statement);
sqlite3_finalize(statement);
m_owner = owner;
mgmtCertificateChanged();
}
string
PibDb::getOwnerName() const
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database, "SELECT owner FROM mgmt", -1, &statement, nullptr);
if (sqlite3_step(statement) == SQLITE_ROW) {
m_owner = sqlite3_column_string(statement, 0);
}
sqlite3_finalize(statement);
return m_owner;
}
shared_ptr<IdentityCertificate>
PibDb::getMgmtCertificate() const
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database, "SELECT local_management_cert FROM mgmt", -1, &statement, nullptr);
shared_ptr<IdentityCertificate> certificate;
if (sqlite3_step(statement) == SQLITE_ROW) {
certificate = make_shared<IdentityCertificate>();
certificate->wireDecode(sqlite3_column_block(statement, 0));
}
sqlite3_finalize(statement);
return certificate;
}
void
PibDb::setTpmLocator(const std::string& tpmLocator)
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"UPDATE mgmt SET tpm_locator=? WHERE owner=?",
-1, &statement, nullptr);
sqlite3_bind_string(statement, 1, tpmLocator, SQLITE_TRANSIENT);
sqlite3_bind_string(statement, 2, m_owner, SQLITE_TRANSIENT);
sqlite3_step(statement);
sqlite3_finalize(statement);
}
std::string
PibDb::getTpmLocator() const
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database, "SELECT tpm_locator FROM mgmt", -1, &statement, nullptr);
string tpmLocator;
if (sqlite3_step(statement) == SQLITE_ROW) {
tpmLocator = sqlite3_column_string(statement, 0);
}
sqlite3_finalize(statement);
return tpmLocator;
}
int64_t
PibDb::addIdentity(const Name& identity)
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"INSERT INTO identities (identity) values (?)",
-1, &statement, nullptr);
sqlite3_bind_block(statement, 1, identity.wireEncode(), SQLITE_TRANSIENT);
sqlite3_step(statement);
sqlite3_finalize(statement);
return sqlite3_last_insert_rowid(m_database);
}
void
PibDb::deleteIdentity(const Name& identity)
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"DELETE FROM identities WHERE identity=?",
-1, &statement, nullptr);
sqlite3_bind_block(statement, 1, identity.wireEncode(), SQLITE_TRANSIENT);
sqlite3_step(statement);
sqlite3_finalize(statement);
}
bool
PibDb::hasIdentity(const Name& identity) const
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"SELECT id FROM identities WHERE identity=?",
-1, &statement, nullptr);
sqlite3_bind_block(statement, 1, identity.wireEncode(), SQLITE_TRANSIENT);
int result = sqlite3_step(statement);
sqlite3_finalize(statement);
if (result == SQLITE_ROW)
return true;
else
return false;
}
void
PibDb::setDefaultIdentity(const Name& identity)
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"UPDATE identities SET is_default=1 WHERE identity=?",
-1, &statement, nullptr);
sqlite3_bind_block(statement, 1, identity.wireEncode(), SQLITE_TRANSIENT);
sqlite3_step(statement);
sqlite3_finalize(statement);
}
Name
PibDb::getDefaultIdentity() const
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"SELECT identity FROM identities WHERE is_default=1",
-1, &statement, nullptr);
Name identity = NON_EXISTING_IDENTITY;
if (sqlite3_step(statement) == SQLITE_ROW && sqlite3_column_bytes(statement, 0) != 0) {
identity = Name(sqlite3_column_block(statement, 0));
}
sqlite3_finalize(statement);
return identity;
}
vector<Name>
PibDb::listIdentities() const
{
vector<Name> identities;
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database, "SELECT identity FROM identities", -1, &statement, nullptr);
identities.clear();
while (sqlite3_step(statement) == SQLITE_ROW) {
Name name(sqlite3_column_block(statement, 0));
identities.push_back(name);
}
sqlite3_finalize(statement);
return identities;
}
int64_t
PibDb::addKey(const Name& keyName, const PublicKey& key)
{
if (keyName.empty())
return 0;
Name&& identity = keyName.getPrefix(-1);
if (!hasIdentity(identity))
addIdentity(identity);
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"INSERT INTO keys (identity_id, key_name, key_type, key_bits) \
values ((SELECT id FROM identities WHERE identity=?), ?, ?, ?)",
-1, &statement, nullptr);
sqlite3_bind_block(statement, 1, identity.wireEncode(), SQLITE_TRANSIENT);
sqlite3_bind_block(statement, 2, keyName.wireEncode(), SQLITE_TRANSIENT);
sqlite3_bind_int(statement, 3, key.getKeyType());
sqlite3_bind_blob(statement, 4, key.get().buf(), key.get().size(), SQLITE_STATIC);
sqlite3_step(statement);
sqlite3_finalize(statement);
return sqlite3_last_insert_rowid(m_database);
}
shared_ptr<PublicKey>
PibDb::getKey(const Name& keyName) const
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"SELECT key_bits FROM keys WHERE key_name=?"
, -1, &statement, nullptr);
sqlite3_bind_block(statement, 1, keyName.wireEncode(), SQLITE_TRANSIENT);
shared_ptr<PublicKey> key;
if (sqlite3_step(statement) == SQLITE_ROW) {
key = make_shared<PublicKey>(static_cast<const uint8_t*>(sqlite3_column_blob(statement, 0)),
sqlite3_column_bytes(statement, 0));
}
sqlite3_finalize(statement);
return key;
}
void
PibDb::deleteKey(const Name& keyName)
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"DELETE FROM keys WHERE key_name=?",
-1, &statement, nullptr);
sqlite3_bind_block(statement, 1, keyName.wireEncode(), SQLITE_TRANSIENT);
sqlite3_step(statement);
sqlite3_finalize(statement);
}
bool
PibDb::hasKey(const Name& keyName) const
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"SELECT id FROM keys WHERE key_name=?",
-1, &statement, nullptr);
sqlite3_bind_block(statement, 1, keyName.wireEncode(), SQLITE_TRANSIENT);
int result = sqlite3_step(statement);
sqlite3_finalize(statement);
if (result == SQLITE_ROW)
return true;
else
return false;
}
void
PibDb::setDefaultKeyNameOfIdentity(const Name& keyName)
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"UPDATE keys SET is_default=1 WHERE key_name=?",
-1, &statement, nullptr);
sqlite3_bind_block(statement, 1, keyName.wireEncode(), SQLITE_TRANSIENT);
sqlite3_step(statement);
sqlite3_finalize(statement);
}
Name
PibDb::getDefaultKeyNameOfIdentity(const Name& identity) const
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"SELECT key_name FROM keys JOIN identities ON keys.identity_id=identities.id\
WHERE identities.identity=? AND keys.is_default=1",
-1, &statement, nullptr);
sqlite3_bind_block(statement, 1, identity.wireEncode(), SQLITE_TRANSIENT);
Name keyName = NON_EXISTING_KEY;
if (sqlite3_step(statement) == SQLITE_ROW && sqlite3_column_bytes(statement, 0) != 0) {
keyName = Name(sqlite3_column_block(statement, 0));
}
sqlite3_finalize(statement);
return keyName;
}
vector<Name>
PibDb::listKeyNamesOfIdentity(const Name& identity) const
{
vector<Name> keyNames;
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"SELECT key_name FROM keys JOIN identities ON keys.identity_id=identities.id\
WHERE identities.identity=?",
-1, &statement, nullptr);
sqlite3_bind_block(statement, 1, identity.wireEncode(), SQLITE_TRANSIENT);
keyNames.clear();
while (sqlite3_step(statement) == SQLITE_ROW) {
Name keyName(sqlite3_column_block(statement, 0));
keyNames.push_back(keyName);
}
sqlite3_finalize(statement);
return keyNames;
}
int64_t
PibDb::addCertificate(const IdentityCertificate& certificate)
{
const Name& certName = certificate.getName();
const Name& keyName = certificate.getPublicKeyName();
if (!hasKey(keyName))
addKey(keyName, certificate.getPublicKeyInfo());
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"INSERT INTO certificates \
(key_id, certificate_name, certificate_data) \
values ((SELECT id FROM keys WHERE key_name=?), ?, ?)",
-1, &statement, nullptr);
sqlite3_bind_block(statement, 1, keyName.wireEncode(), SQLITE_TRANSIENT);
sqlite3_bind_block(statement, 2, certName.wireEncode(), SQLITE_TRANSIENT);
sqlite3_bind_block(statement, 3, certificate.wireEncode(), SQLITE_STATIC);
sqlite3_step(statement);
sqlite3_finalize(statement);
return sqlite3_last_insert_rowid(m_database);
}
shared_ptr<IdentityCertificate>
PibDb::getCertificate(const Name& certificateName) const
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"SELECT certificate_data FROM certificates WHERE certificate_name=?",
-1, &statement, nullptr);
sqlite3_bind_block(statement, 1, certificateName.wireEncode(), SQLITE_TRANSIENT);
shared_ptr<IdentityCertificate> certificate;
if (sqlite3_step(statement) == SQLITE_ROW) {
certificate = make_shared<IdentityCertificate>();
certificate->wireDecode(sqlite3_column_block(statement, 0));
}
sqlite3_finalize(statement);
return certificate;
}
void
PibDb::deleteCertificate(const Name& certificateName)
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"DELETE FROM certificates WHERE certificate_name=?",
-1, &statement, nullptr);
sqlite3_bind_block(statement, 1, certificateName.wireEncode(), SQLITE_TRANSIENT);
sqlite3_step(statement);
sqlite3_finalize(statement);
}
bool
PibDb::hasCertificate(const Name& certificateName) const
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"SELECT id FROM certificates WHERE certificate_name=?",
-1, &statement, nullptr);
sqlite3_bind_block(statement, 1, certificateName.wireEncode(), SQLITE_TRANSIENT);
int result = sqlite3_step(statement);
sqlite3_finalize(statement);
if (result == SQLITE_ROW)
return true;
else
return false;
}
void
PibDb::setDefaultCertNameOfKey(const Name& certificateName)
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"UPDATE certificates SET is_default=1 WHERE certificate_name=?",
-1, &statement, nullptr);
sqlite3_bind_block(statement, 1, certificateName.wireEncode(), SQLITE_TRANSIENT);
sqlite3_step(statement);
sqlite3_finalize(statement);
}
Name
PibDb::getDefaultCertNameOfKey(const Name& keyName) const
{
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"SELECT certificate_name\
FROM certificates JOIN keys ON certificates.key_id=keys.id\
WHERE keys.key_name=? AND certificates.is_default=1",
-1, &statement, nullptr);
sqlite3_bind_block(statement, 1, keyName.wireEncode(), SQLITE_TRANSIENT);
Name certName = NON_EXISTING_CERTIFICATE;
if (sqlite3_step(statement) == SQLITE_ROW && sqlite3_column_bytes(statement, 0) != 0) {
certName = Name(sqlite3_column_block(statement, 0));
}
sqlite3_finalize(statement);
return certName;
}
vector<Name>
PibDb::listCertNamesOfKey(const Name& keyName) const
{
vector<Name> certNames;
sqlite3_stmt* statement;
sqlite3_prepare_v2(m_database,
"SELECT certificate_name\
FROM certificates JOIN keys ON certificates.key_id=keys.id\
WHERE keys.key_name=?",
-1, &statement, nullptr);
sqlite3_bind_block(statement, 1, keyName.wireEncode(), SQLITE_TRANSIENT);
certNames.clear();
while (sqlite3_step(statement) == SQLITE_ROW) {
Name name(sqlite3_column_block(statement, 0));
certNames.push_back(name);
}
sqlite3_finalize(statement);
return certNames;
}
} // namespace pib
} // namespace ndn
+265
View File
@@ -0,0 +1,265 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#ifndef NDN_TOOLS_PIB_PIB_DB_HPP
#define NDN_TOOLS_PIB_PIB_DB_HPP
#include "core/common.hpp"
#include <ndn-cxx/security/identity-certificate.hpp>
#include <ndn-cxx/util/signal.hpp>
#include <set>
#include <vector>
struct sqlite3;
struct sqlite3_context;
struct Mem;
typedef Mem sqlite3_value;
namespace ndn {
namespace pib {
/// @brief Callback to report changes on user info.
typedef function<void(const std::string&)> UserChangedEventHandler;
/// @brief Callback to report that a key is deleted.
typedef function<void(const std::string&, const Name&,
const name::Component&)> KeyDeletedEventHandler;
/**
* @brief PibDb is a class to manage the database of PIB service.
*
* only public key related information is stored in this database.
* Detail information can be found at:
* http://redmine.named-data.net/projects/ndn-cxx/wiki/PublicKey_Info_Base
*/
class PibDb : noncopyable
{
public:
util::signal::Signal<PibDb> mgmtCertificateChanged;
util::signal::Signal<PibDb, Name> certificateDeleted;
util::signal::Signal<PibDb, Name> keyDeleted;
util::signal::Signal<PibDb, Name> identityDeleted;
util::signal::Signal<PibDb, Name> certificateInserted;
public:
class Error : public std::runtime_error
{
public:
explicit
Error(const std::string& what)
: std::runtime_error(what)
{
}
};
explicit
PibDb(const std::string& dbDir = "");
public: // Owner management
/**
* @brief Update owner's management certificate
*
* Since owner name is encoded in the management certificate,
* this method can also set the owner name if it is not set.
* If the owner name is set but does not match the one in the
* supplied certificate, it throws @p Error.
*
* @throws Error if supplied certificate is wrong
*/
void
updateMgmtCertificate(const IdentityCertificate& certificate);
/**
* @brief Get owner name
*
* return empty string when owner name is not set.
*/
std::string
getOwnerName() const;
/** @brief Get the management cert
*
* return nullptr when the management cert is not set
*/
shared_ptr<IdentityCertificate>
getMgmtCertificate() const;
/// @brief Set TPM locator
void
setTpmLocator(const std::string& tpmLocator);
/**
* @brief Get TPM locator
*
* return empty string when tpmLocator is not set.
*/
std::string
getTpmLocator() const;
public: // Identity management
/**
* @brief Add an identity
*
* @return row id of the added identity, 0 if insert fails.
*/
int64_t
addIdentity(const Name& identity);
/// @brief Delete an identity
void
deleteIdentity(const Name& identity);
/// @brief Check if an identity exists
bool
hasIdentity(const Name& identity) const;
/// @brief Get all identities
std::vector<Name>
listIdentities() const;
/// @brief Set the default identity
void
setDefaultIdentity(const Name& identity);
/**
* @brief Get the default identity
*
* @return default identity or /localhost/reserved/non-existing-identity if no default identity
*/
Name
getDefaultIdentity() const;
public: // Key management
/// @brief Add key
int64_t
addKey(const Name& keyName, const PublicKey& key);
/// @brief Delete key
void
deleteKey(const Name& keyName);
/// @brief Check if a key exists
bool
hasKey(const Name& keyName) const;
/**
* @brief Get key
*
* @return shared pointer to the key, nullptr if the key does not exit
*/
shared_ptr<PublicKey>
getKey(const Name& keyName) const;
/// @brief Get all the key names of an identity
std::vector<Name>
listKeyNamesOfIdentity(const Name& identity) const;
/// @brief Set an identity's default key name
void
setDefaultKeyNameOfIdentity(const Name& keyName);
/**
* @brief Get the default key name of an identity
*
* @return default key name or /localhost/reserved/non-existing-key if no default key
*/
Name
getDefaultKeyNameOfIdentity(const Name& identity) const;
public: // Certificate management
/// @brief Add a certificate
int64_t
addCertificate(const IdentityCertificate& certificate);
/// @brief Delete a certificate
void
deleteCertificate(const Name& certificateName);
/// @brief Check if the certificate exist
bool
hasCertificate(const Name& certificateName) const;
/**
* @brief Get a certificate
*
* @return shared pointer to the certificate, nullptr if the certificate does not exist
*/
shared_ptr<IdentityCertificate>
getCertificate(const Name& certificateName) const;
/// @brief Get all the cert names of a key
std::vector<Name>
listCertNamesOfKey(const Name& keyName) const;
/// @brief Set a key's default certificate name
void
setDefaultCertNameOfKey(const Name& certificateName);
/**
* @brief Get a key's default certificate name
*
* @return default certificate name or /localhost/reserved/non-existing-certificate if no default
* certificate.
*/
Name
getDefaultCertNameOfKey(const Name& keyName) const;
private:
void
createDbDeleteTrigger();
private:
static void
identityDeletedFun(sqlite3_context* context, int argc, sqlite3_value** argv);
static void
keyDeletedFun(sqlite3_context* context, int argc, sqlite3_value** argv);
static void
certDeletedFun(sqlite3_context* context, int argc, sqlite3_value** argv);
static void
certInsertedFun(sqlite3_context* context, int argc, sqlite3_value** argv);
public:
static const Name NON_EXISTING_IDENTITY;
static const Name NON_EXISTING_KEY;
static const Name NON_EXISTING_CERTIFICATE;
private:
static const Name LOCALHOST_PIB;
static const name::Component MGMT_LABEL;
private:
sqlite3* m_database;
mutable std::string m_owner;
};
} // namespace pib
} // namespace ndn
#endif // NDN_TOOLS_PIB_PIB_DB_HPP
+163
View File
@@ -0,0 +1,163 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* @author Yingdi Yu <yingdi@cs.ucla.edu>
*/
#include "pib-validator.hpp"
#include "encoding/pib-common.hpp"
#include "encoding/update-param.hpp"
#include <set>
#include <string>
namespace ndn {
namespace pib {
using std::set;
using std::string;
PibValidator::PibValidator(const PibDb& db, size_t maxCacheSize)
: m_db(db)
, m_isMgmtReady(false)
{
m_owner = m_db.getOwnerName();
m_mgmtCert = m_db.getMgmtCertificate();
if (!m_owner.empty() && m_mgmtCert != nullptr)
m_isMgmtReady = true;
m_mgmtChangeConnection =
const_cast<PibDb&>(m_db).mgmtCertificateChanged.connect([this] () {
m_owner = m_db.getOwnerName();
m_mgmtCert = m_db.getMgmtCertificate();
if (!m_owner.empty() && m_mgmtCert != nullptr)
m_isMgmtReady = true;
});
m_keyDeletedConnection =
const_cast<PibDb&>(m_db).keyDeleted.connect([this] (Name keyName) {
m_keyCache.erase(keyName);
});
}
PibValidator::~PibValidator()
{
}
void
PibValidator::checkPolicy(const Interest& interest,
int nSteps,
const OnInterestValidated& onValidated,
const OnInterestValidationFailed& onValidationFailed,
std::vector<shared_ptr<ValidationRequest>>& nextSteps)
{
if (!m_isMgmtReady)
return onValidationFailed(interest.shared_from_this(), "PibDb is not initialized");
const Name& interestName = interest.getName();
if (interestName.size() != SIGNED_PIB_INTEREST_SIZE) {
return onValidationFailed(interest.shared_from_this(),
"Interest is not signed: " + interest.getName().toUri());
}
// Check if the user exists in PIB
string user = interestName.get(OFFSET_USER).toUri();
if (user != m_owner)
return onValidationFailed(interest.shared_from_this(), "Wrong user: " + user);
// Verify signature
try {
Signature signature(interestName[OFFSET_SIG_INFO].blockFromValue(),
interestName[OFFSET_SIG_VALUE].blockFromValue());
// KeyLocator is required to contain the name of signing certificate (w/o version)
if (!signature.hasKeyLocator())
return onValidationFailed(interest.shared_from_this(), "No valid KeyLocator");
const KeyLocator& keyLocator = signature.getKeyLocator();
if (keyLocator.getType() != KeyLocator::KeyLocator_Name)
return onValidationFailed(interest.shared_from_this(), "Key Locator is not a name");
// Check if PIB has the corresponding public key
shared_ptr<PublicKey> publicKey;
if (keyLocator.getName() == m_mgmtCert->getName().getPrefix(-1)) {
// the signing key is mgmt key.
publicKey = make_shared<PublicKey>(m_mgmtCert->getPublicKeyInfo());
}
else {
// the signing key is normal key.
Name keyName = IdentityCertificate::certificateNameToPublicKeyName(keyLocator.getName());
shared_ptr<PublicKey> key = m_keyCache.find(keyName);
if (key != nullptr) {
// the signing key is cached.
publicKey = key;
}
else {
// the signing key is not cached.
publicKey = m_db.getKey(keyName);
if (publicKey == nullptr) {
// the signing key does not exist in PIB.
return onValidationFailed(interest.shared_from_this(), "Public key is not trusted");
}
else {
// the signing key is retrieved from PIB.
m_keyCache.insert(keyName, publicKey);
}
}
}
if (verifySignature(interest, signature, *publicKey))
onValidated(interest.shared_from_this());
else
onValidationFailed(interest.shared_from_this(), "Cannot verify signature");
}
catch (KeyLocator::Error&) {
return onValidationFailed(interest.shared_from_this(),
"No valid KeyLocator");
}
catch (Signature::Error&) {
return onValidationFailed(interest.shared_from_this(),
"No valid signature");
}
catch (IdentityCertificate::Error&) {
return onValidationFailed(interest.shared_from_this(),
"Cannot determine the signing key");
}
catch (tlv::Error&) {
return onValidationFailed(interest.shared_from_this(),
"Cannot decode signature");
}
}
void
PibValidator::checkPolicy(const Data& data,
int nSteps,
const OnDataValidated& onValidated,
const OnDataValidationFailed& onValidationFailed,
std::vector<shared_ptr<ValidationRequest>>& nextSteps)
{
// Pib does not express any interest, therefor should not validate any data.
onValidationFailed(data.shared_from_this(),
"PibValidator should not receive data packet");
}
} // namespace pib
} // namespace ndn

Some files were not shown because too many files have changed in this diff Show More