Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 799390a4e4 | |||
| f8852b3206 | |||
| d4ab87fb12 | |||
| 277ecf085e | |||
| 821a01431b | |||
| ae2c9f73ad | |||
| 672b9a7093 | |||
| 28ae2cbee0 | |||
| 3e79c9cda4 | |||
| e02fb52090 | |||
| c8a0a25a67 | |||
| ef1e276b11 | |||
| 8a3081f973 | |||
| 1e7a7b20c9 | |||
| 7f43c53c2a | |||
| 357c205aa6 | |||
| 6fbb7b4594 | |||
| a93680e5b7 | |||
| 0a312e5126 | |||
| 77627ab8ce | |||
| 4bd28fc839 | |||
| 0f0bc4b5b2 |
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
@@ -22,7 +22,7 @@
|
||||
namespace ndn {
|
||||
namespace tools {
|
||||
|
||||
const char VERSION[] = "0.1.0-dev";
|
||||
const char VERSION[] = "0.2";
|
||||
|
||||
} // namespace tools
|
||||
} // namespace ndn
|
||||
|
||||
@@ -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),
|
||||
]
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
--------
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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.
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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')
|
||||
|
||||
@@ -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*
|
||||
@@ -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")
|
||||
@@ -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,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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user